From 181df5032fac2e8e85618ea06dcc13f40d0ef927 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Jan 2006 15:12:18 +0000 Subject: r13132: Old fix from Lars tx --- packaging/Debian/debian-unstable/samba-common.dhcp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packaging/Debian/debian-unstable/samba-common.dhcp b/packaging/Debian/debian-unstable/samba-common.dhcp index 3b5a05ff573..38743a4568a 100644 --- a/packaging/Debian/debian-unstable/samba-common.dhcp +++ b/packaging/Debian/debian-unstable/samba-common.dhcp @@ -1,6 +1,7 @@ #!/bin/sh SAMBA_DHCP_CONF=/etc/samba/dhcp.conf +SAMBA_DHCP_CONF_INFO_FILE="" netbios_setup() { # No need to continue if we're called with an unsupported option @@ -15,6 +16,7 @@ netbios_setup() { # Nor should we continue if no settings have changed if [ "$new_netbios_name_servers" = "$old_netbios_name_servers" ] \ && [ "$new_netbios_scope" = "$old_netbios_scope" ] + && [ -f $SAMBA_DHCP_CONF ] then return fi @@ -33,6 +35,8 @@ netbios_setup() { done echo -n > $SAMBA_DHCP_CONF + test -n "$SAMBA_DHCP_CONF_INFO_FILE" -a -f "$SAMBA_DHCP_CONF_INFO_FILE" && \ + cat "$SAMBA_DHCP_CONF_INFO_FILE" >> $SAMBA_DHCP_CONF # If we're updating on failure/expire, AND there are no WINS # servers for other interfaces, leave the file empty. -- cgit From 9415d0dd4dc80b7e515a3ad3e6d8138578d4f731 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 25 Jan 2006 15:43:15 +0000 Subject: r13133: patch from Makr Proehl for dumping server role when calling 'testparm -s' (BUG 1336) --- source/utils/testparm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/utils/testparm.c b/source/utils/testparm.c index f5c835725a4..11ce960e557 100644 --- a/source/utils/testparm.c +++ b/source/utils/testparm.c @@ -349,7 +349,7 @@ print command parameter is ignored when using CUPS libraries.\n", } - if (!silent_mode && !section_name && !parameter_name) { + if (!section_name && !parameter_name) { fprintf(stderr,"Server role: %s\n", server_role_str(lp_server_role())); } -- cgit From d04664fe0d63d000562b8db4c3291e16d95c6650 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Jan 2006 21:24:51 +0000 Subject: r13136: Fix handling user sid and user gid --- source/utils/pdbedit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/utils/pdbedit.c b/source/utils/pdbedit.c index ddf0eea169b..53d3b17d064 100644 --- a/source/utils/pdbedit.c +++ b/source/utils/pdbedit.c @@ -28,7 +28,7 @@ #define BIT_SPSTYLE 0x00000010 #define BIT_CAN_CHANGE 0x00000020 #define BIT_MUST_CHANGE 0x00000040 -#define BIT_RESERV_3 0x00000080 +#define BIT_USERSIDS 0x00000080 #define BIT_FULLNAME 0x00000100 #define BIT_HOMEDIR 0x00000200 #define BIT_HDIRDRIVE 0x00000400 @@ -52,7 +52,7 @@ #define BIT_LOGONHOURS 0x10000000 #define MASK_ALWAYS_GOOD 0x0000001F -#define MASK_USER_GOOD 0x00405F60 +#define MASK_USER_GOOD 0x00405FE0 /********************************************************* Add all currently available users to another db @@ -819,6 +819,8 @@ int main (int argc, char **argv) (user_name ? BIT_USER : 0) + (list_users ? BIT_LIST : 0) + (force_initialised_password ? BIT_FIX_INIT : 0) + + (user_sid ? BIT_USERSIDS : 0) + + (group_sid ? BIT_USERSIDS : 0) + (modify_user ? BIT_MODIFY : 0) + (add_user ? BIT_CREATE : 0) + (delete_user ? BIT_DELETE : 0) + -- cgit From c1f20a5613afc64547185f5edb48fd41a4376c1f Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Jan 2006 21:25:25 +0000 Subject: r13137: make cleare where long ifdefs ends --- source/libads/sasl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/libads/sasl.c b/source/libads/sasl.c index 44a95f59908..f6adfb51086 100644 --- a/source/libads/sasl.c +++ b/source/libads/sasl.c @@ -419,7 +419,7 @@ failed: ber_bvfree(scred); return status; } -#endif +#endif /* HAVE_GGSAPI */ /* mapping between SASL mechanisms and functions */ static struct { @@ -466,5 +466,5 @@ ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads) return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED); } -#endif +#endif /* HAVE_LDAP */ -- cgit From bccb422133535324be0208b849b45002887c9815 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Jan 2006 21:29:36 +0000 Subject: r13138: old fix I forgot to commit need to access info when using the ldap backend --- source/rpc_server/srv_samr_nt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index 8f8c035c9cd..2f9d494a26f 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -4495,8 +4495,11 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_ if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_GROUP_SET_INFO, "_samr_set_groupinfo"))) { return r_u->status; } - - if (!get_domain_group_from_sid(group_sid, &map)) + + become_root(); + ret = get_domain_group_from_sid(group_sid, &map); + unbecome_root(); + if (!ret) return NT_STATUS_NO_SUCH_GROUP; ctr=q_u->ctr; -- cgit From 8597d7b71487440aa15ea4cafed19559b9058510 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 25 Jan 2006 21:58:06 +0000 Subject: r13140: Fix swat - make sure it can list running services (ensure loopback_ip) is defined. Jerry - this needs to be in 3.0.21b. Jeremy. --- source/web/swat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/web/swat.c b/source/web/swat.c index 3806291a6ad..372d473bdb5 100644 --- a/source/web/swat.c +++ b/source/web/swat.c @@ -1373,6 +1373,7 @@ static void printers_page(void) setup_logging(argv[0],False); load_config(True); + load_interfaces(); iNumNonAutoPrintServices = lp_numservices(); load_printers(); -- cgit From 65d0541e8310f2c5afe847f89f8c07b3c38d83bb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 25 Jan 2006 23:00:07 +0000 Subject: r13147: Raise creds_server_step fail log messages to debug level 2. These can happen in normal operation (I think - not 100% sure) and don't want to alarm admins. Jerry please add this to 3.0.21b. Jeremy. --- source/libsmb/credentials.c | 2 +- source/rpc_server/srv_netlog_nt.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c index edb242df7e8..ad06cd9015f 100644 --- a/source/libsmb/credentials.c +++ b/source/libsmb/credentials.c @@ -156,7 +156,7 @@ BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) { DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data))); DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data))); - DEBUG(0,("creds_server_check: credentials check failed.\n")); + DEBUG(2,("creds_server_check: credentials check failed.\n")); return False; } DEBUG(10,("creds_server_check: credentials check OK.\n")); diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c index d0d47be9f29..643921f5963 100644 --- a/source/rpc_server/srv_netlog_nt.c +++ b/source/rpc_server/srv_netlog_nt.c @@ -470,7 +470,7 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET * /* Step the creds chain forward. */ if (!creds_server_step(p->dc, &q_u->clnt_id.cred, &cred_out)) { - DEBUG(0,("_net_srv_pwset: creds_server_step failed. Rejecting auth " + DEBUG(2,("_net_srv_pwset: creds_server_step failed. Rejecting auth " "request from client %s machine account %s\n", p->dc->remote_machine, p->dc->mach_acct )); return NT_STATUS_ACCESS_DENIED; @@ -573,7 +573,7 @@ NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOF /* checks and updates credentials. creates reply credentials */ if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) { - DEBUG(0,("_net_sam_logoff: creds_server_step failed. Rejecting auth " + DEBUG(2,("_net_sam_logoff: creds_server_step failed. Rejecting auth " "request from client %s machine account %s\n", p->dc->remote_machine, p->dc->mach_acct )); return NT_STATUS_ACCESS_DENIED; @@ -662,7 +662,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * /* checks and updates credentials. creates reply credentials */ if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) { - DEBUG(0,("_net_sam_logon: creds_server_step failed. Rejecting auth " + DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth " "request from client %s machine account %s\n", p->dc->remote_machine, p->dc->mach_acct )); return NT_STATUS_ACCESS_DENIED; -- cgit From de8e43fe35d80b2a8f01e5b45d49c44f4adbcbca Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 26 Jan 2006 00:14:25 +0000 Subject: r13148: Fix bug: #3413 Check that ldap admin dn is defined in smb.conf before setting the ldap password in secrets.tdb Based on patch by William Jojo Simo. --- source/utils/smbpasswd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c index 7659bb2997a..29189c5febd 100644 --- a/source/utils/smbpasswd.c +++ b/source/utils/smbpasswd.c @@ -327,14 +327,20 @@ static int process_root(int local_flags) char *old_passwd = NULL; if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) { - printf("Setting stored password for \"%s\" in secrets.tdb\n", - lp_ldap_admin_dn()); + char *ldap_admin_dn = lp_ldap_admin_dn(); + if ( ! *ldap_admin_dn ) { + DEBUG(0,("ERROR: 'ldap admin dn' not defined! Please check your smb.conf\n")); + goto done; + } + + printf("Setting stored password for \"%s\" in secrets.tdb\n", ldap_admin_dn); if ( ! *ldap_secret ) { new_passwd = prompt_for_new_password(stdin_passwd_get); fstrcpy(ldap_secret, new_passwd); } - if (!store_ldap_admin_pw(ldap_secret)) + if (!store_ldap_admin_pw(ldap_secret)) { DEBUG(0,("ERROR: Failed to store the ldap admin password!\n")); + } goto done; } -- cgit From 7bf26dcc5f9c47823214aec86b73395db65fc171 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 26 Jan 2006 12:04:43 +0000 Subject: r13162: Allow to set the flags for a ds_enum_domain_trusts query in rpcclient. Guenther --- source/rpcclient/cmd_ds.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/rpcclient/cmd_ds.c b/source/rpcclient/cmd_ds.c index 951d18a710e..478b9f89e79 100644 --- a/source/rpcclient/cmd_ds.c +++ b/source/rpcclient/cmd_ds.c @@ -52,11 +52,15 @@ static NTSTATUS cmd_ds_enum_domain_trusts(struct rpc_pipe_client *cli, const char **argv) { NTSTATUS result; - uint32 flags = 0x1; + uint32 flags = DS_DOMAIN_IN_FOREST; struct ds_domain_trust *trusts = NULL; unsigned int num_domains = 0; int i; + if (argc > 1) { + flags = atoi(argv[1]); + } + result = rpccli_ds_enum_domain_trusts( cli, mem_ctx, cli->cli->desthost, flags, &trusts, &num_domains ); -- cgit From 7bd90c026009cb4976081e58e2efbf2881e8c4d2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 26 Jan 2006 23:55:26 +0000 Subject: r13172: Fix incorrect error message when new tdb not created correctly. Jeremy. --- source/passdb/pdb_tdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index 8bf9b1b2828..d58187ffe5b 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -420,7 +420,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT * TDB file doesn't exist, so try to create new one. This is useful to avoid * confusing error msg when adding user account first time */ - if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT ))) { + if ((pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT )) != NULL) { DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n", tdb_state->tdbsam_location)); } else { -- cgit From 98749b24628e7edacaaff77ee0c03a98fd7c5def Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 00:09:03 +0000 Subject: r13175: Actually make adding a new user into an empty pdbtdb file create the file. Jeremy. --- source/passdb/pdb_tdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index d58187ffe5b..164ec722998 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -420,7 +420,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT * TDB file doesn't exist, so try to create new one. This is useful to avoid * confusing error msg when adding user account first time */ - if ((pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT )) != NULL) { + if ((pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT|O_RDWR )) != NULL) { DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n", tdb_state->tdbsam_location)); } else { -- cgit From 51614b45e1d40af398fa2315f2c80f70c92c60fe Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 02:35:08 +0000 Subject: r13176: Fix show-stopper bug for 3.0.21b where 4 leg NTLMSSP SPNEGO auth was not generating the correct auth header on the 4th packet. This may fix a lot of Windows client complaints and is essential for release. Jeremy. --- source/libsmb/spnego.c | 1 - source/rpc_server/srv_pipe.c | 25 ++++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/source/libsmb/spnego.c b/source/libsmb/spnego.c index 6cc4436a0cf..f6a66200bac 100644 --- a/source/libsmb/spnego.c +++ b/source/libsmb/spnego.c @@ -341,4 +341,3 @@ BOOL free_spnego_data(SPNEGO_DATA *spnego) out: return ret; } - diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c index 8084e7673a5..ecf79d0c1f3 100644 --- a/source/rpc_server/srv_pipe.c +++ b/source/rpc_server/srv_pipe.c @@ -1188,12 +1188,17 @@ static BOOL pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_ static BOOL pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p, RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) { - DATA_BLOB spnego_blob, auth_blob, auth_reply; + RPC_HDR_AUTH auth_info; + DATA_BLOB spnego_blob; + DATA_BLOB auth_blob; + DATA_BLOB auth_reply; + DATA_BLOB response; AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state; ZERO_STRUCT(spnego_blob); ZERO_STRUCT(auth_blob); ZERO_STRUCT(auth_reply); + ZERO_STRUCT(response); if (p->auth.auth_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP || !a) { DEBUG(0,("pipe_spnego_auth_bind_continue: not in NTLMSSP auth state.\n")); @@ -1230,7 +1235,24 @@ static BOOL pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p data_blob_free(&spnego_blob); data_blob_free(&auth_blob); + + /* Generate the spnego "accept completed" blob - no incoming data. */ + response = spnego_gen_auth_response(&auth_reply, NT_STATUS_OK, OID_NTLMSSP); + + /* Copy the blob into the pout_auth parse struct */ + init_rpc_hdr_auth(&auth_info, RPC_SPNEGO_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1); + if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) { + DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of RPC_HDR_AUTH failed.\n")); + goto err; + } + + if (!prs_copy_data_in(pout_auth, (char *)response.data, response.length)) { + DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of data blob failed.\n")); + goto err; + } + data_blob_free(&auth_reply); + data_blob_free(&response); p->pipe_bound = True; @@ -1241,6 +1263,7 @@ static BOOL pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p data_blob_free(&spnego_blob); data_blob_free(&auth_blob); data_blob_free(&auth_reply); + data_blob_free(&response); free_pipe_ntlmssp_auth_data(&p->auth); p->auth.a_u.auth_ntlmssp_state = NULL; -- cgit From 97578a3d746020709c985c02a67fb6e5ab497260 Mon Sep 17 00:00:00 2001 From: Jim McDonough Date: Fri, 27 Jan 2006 15:14:55 +0000 Subject: r13187: IBM Tivoli Directory Server schema updates from John Janosik --- examples/LDAP/samba.schema.at.IBM-DS | 21 +++++++++++++++++++++ examples/LDAP/samba.schema.oc.IBM-DS | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/examples/LDAP/samba.schema.at.IBM-DS b/examples/LDAP/samba.schema.at.IBM-DS index 375a0baede6..4f4c0567a91 100644 --- a/examples/LDAP/samba.schema.at.IBM-DS +++ b/examples/LDAP/samba.schema.at.IBM-DS @@ -76,3 +76,24 @@ attributetypes=( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hour attributetypes=( 1.3.6.1.4.1.7165.2.1.56 NAME 'sambaAccountPolicyName' DESC 'Account Policy Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) attributetypes=( 1.3.6.1.4.1.7165.2.1.57 NAME 'sambaAccountPolicyValue' DESC 'Account Policy Value' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + diff --git a/examples/LDAP/samba.schema.oc.IBM-DS b/examples/LDAP/samba.schema.oc.IBM-DS index 2b00a5e8c64..575aed4b1a2 100644 --- a/examples/LDAP/samba.schema.oc.IBM-DS +++ b/examples/LDAP/samba.schema.oc.IBM-DS @@ -4,7 +4,7 @@ objectclasses=( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY objectclasses=( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList )) -objectclasses=( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase ) ) +objectclasses=( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange ) ) objectclasses=( 1.3.6.1.4.1.7165.1.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) ) -- cgit From a40dc613a41fa8672ff7923789a6cd1c4208cbc9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 19:24:37 +0000 Subject: r13190: Fix #3458 from Andriy Gapon . Don't access free'd memory. Jerry please pick up for 3.0.21b ! Jeremy. --- source/passdb/secrets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index c173a5ea868..14896a33400 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -299,7 +299,6 @@ BOOL secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], *pass_last_set_time = pass->mod_time; } memcpy(ret_pwd, pass->hash, 16); - SAFE_FREE(pass); if (channel) { *channel = get_default_sec_channel(); @@ -313,6 +312,7 @@ BOOL secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], } } + SAFE_FREE(pass); return True; } -- cgit From 74a8af4bc57c28facf4da25f6b1e850ed9369471 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 19:54:39 +0000 Subject: r13192: Fix up alignment issues when printing share mode entries. Add paranioa to debug so we know when an entry is unused. Jeremy. --- source/locking/locking.c | 12 ++++++++---- source/smbd/oplock.c | 9 +++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index 9a13e099dbf..770ef918b89 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -384,11 +384,13 @@ char *share_mode_str(int num, struct share_mode_entry *e) { static pstring share_str; - slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: " + slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: %s " "pid = %s, share_access = 0x%x, private_options = 0x%x, " "access_mask = 0x%x, mid = 0x%x, type= 0x%x, file_id = %lu, " "dev = 0x%x, inode = %.0f", - num, procid_str_static(&e->pid), + num, + e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "", + procid_str_static(&e->pid), e->share_access, e->private_options, e->access_mask, e->op_mid, e->op_type, e->share_file_id, (unsigned int)e->dev, (double)e->inode ); @@ -408,9 +410,11 @@ static void print_share_mode_table(struct locking_data *data) int i; for (i = 0; i < num_share_modes; i++) { - struct share_mode_entry *entry_p = &shares[i]; + struct share_mode_entry entry; + + memcpy(&entry, &shares[i], sizeof(struct share_mode_entry)); DEBUG(10,("print_share_mode_table: %s\n", - share_mode_str(i, entry_p))); + share_mode_str(i, &entry))); } } diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 6739d29470b..234b62e8ae4 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -684,6 +684,11 @@ void release_level_2_oplocks_on_change(files_struct *fsp) don't have to do anything */ for (i=0; inum_share_modes; i++) { struct share_mode_entry *e = &lck->share_modes[i]; + + if (!is_valid_share_mode_entry(e)) { + continue; + } + if ((e->op_type == NO_OPLOCK) && (e->share_file_id == fsp->file_id) && (e->dev == fsp->dev) && @@ -701,6 +706,10 @@ void release_level_2_oplocks_on_change(files_struct *fsp) struct share_mode_entry *share_entry = &lck->share_modes[i]; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; + if (!is_valid_share_mode_entry(share_entry)) { + continue; + } + /* * As there could have been multiple writes waiting at the * lock_share_entry gate we may not be the first to -- cgit From f513fbb1b6a0ff7865cce4f9d8530bce6a64fea6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 19:59:48 +0000 Subject: r13194: Don't do extra memcpy's unless we're asked to. Jeremy. --- source/locking/locking.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index 770ef918b89..be1e83121b7 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -547,7 +547,11 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) offset += sp_len + 1; safe_strcpy(result.dptr + offset, lck->filename, result.dsize - offset - 1); - print_share_mode_table(data); + + if (DEBUGLEVEL >= 10) { + print_share_mode_table(data); + } + return result; } -- cgit From a9d370bb8d82b86b52eba7d055abefdd974725cd Mon Sep 17 00:00:00 2001 From: Lars Müller Date: Fri, 27 Jan 2006 21:49:01 +0000 Subject: r13197: Add -k switch to dump the data of a single key. --- source/tdb/tdbdump.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/source/tdb/tdbdump.c b/source/tdb/tdbdump.c index 6cac0bc5ccd..b702fb07355 100644 --- a/source/tdb/tdbdump.c +++ b/source/tdb/tdbdump.c @@ -59,9 +59,10 @@ static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *stat return 0; } -static int dump_tdb(const char *fname) +static int dump_tdb(const char *fname, const char *keyname) { TDB_CONTEXT *tdb; + TDB_DATA key, value; tdb = tdb_open(fname, 0, 0, O_RDONLY, 0); if (!tdb) { @@ -69,20 +70,55 @@ static int dump_tdb(const char *fname) return 1; } - tdb_traverse(tdb, traverse_fn, NULL); + if (!keyname) { + tdb_traverse(tdb, traverse_fn, NULL); + } else { + key.dptr = (char *)keyname; + key.dsize = strlen( keyname); + value = tdb_fetch(tdb, key); + if (!value.dptr) { + return 1; + } else { + print_data(value); + free(value.dptr); + } + } + return 0; } +static void usage( void) +{ + printf( "Usage: tdbdump [options] \n\n"); + printf( " -h this help message\n"); + printf( " -k keyname dumps value of keyname\n"); +} + int main(int argc, char *argv[]) { - char *fname; + char *fname, *keyname=NULL; + int c; if (argc < 2) { printf("Usage: tdbdump \n"); exit(1); } - fname = argv[1]; + while ((c = getopt( argc, argv, "hk:")) != -1) { + switch (c) { + case 'h': + usage(); + exit( 0); + case 'k': + keyname = optarg; + break; + default: + usage(); + exit( 1); + } + } + + fname = argv[optind]; - return dump_tdb(fname); + return dump_tdb(fname, keyname); } -- cgit From 3e029ecf08ee8db1d6f82ae827e6a704c2f4f48c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Jan 2006 23:30:30 +0000 Subject: r13198: Fix issues exposed by Jerry's testing on 64-bit Solaris (I hope). Separate 3.0.21b patch sent to Jerry. Jeremy. --- source/include/smb.h | 1 - source/locking/locking.c | 22 ------ source/smbd/oplock.c | 193 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 138 insertions(+), 78 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index f899a71dc6d..fba02565d8f 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -549,7 +549,6 @@ struct current_user #define NO_BREAK_SENT 0 #define BREAK_TO_NONE_SENT 1 #define LEVEL_II_BREAK_SENT 2 -#define ASYNC_LEVEL_II_BREAK_SENT 3 typedef struct { fstring smb_name; /* user name from the client */ diff --git a/source/locking/locking.c b/source/locking/locking.c index be1e83121b7..e31ead30e4e 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -988,28 +988,6 @@ BOOL downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp) return True; } - -/******************************************************************* - We've just told all the smbd's that our level2 or fake level2 has been - written to. -********************************************************************/ -BOOL remove_all_share_oplocks(struct share_mode_lock *lck, files_struct *fsp) -{ - int i; - for (i=0; inum_share_modes; i++) { - struct share_mode_entry *e = &lck->share_modes[i]; - if (!is_valid_share_mode_entry(e)) { - continue; - } - if (e->op_type == NO_OPLOCK) { - continue; - } - e->op_type = NO_OPLOCK; - lck->modified = True; - } - return True; -} - /**************************************************************************** Deal with the internal needs of setting the delete on close flag. Note that as the tdb locking is recursive, it is safe to call this from within diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 234b62e8ae4..86f5e1a47cf 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -372,12 +372,129 @@ static void oplock_timeout_handler(struct timed_event *te, { files_struct *fsp = private_data; - DEBUG(0, ("Oplock break failed -- replying anyway\n")); + DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name)); global_client_failed_oplock_break = True; remove_oplock(fsp); reply_to_oplock_break_requests(fsp); } +/******************************************************************* + Add a timeout handler waiting for the client reply. +*******************************************************************/ + +static void add_oplock_timeout_handler(files_struct *fsp) +{ + if (fsp->oplock_timeout != NULL) { + DEBUG(0, ("Logic problem -- have an oplock event hanging " + "around\n")); + } + + fsp->oplock_timeout = + add_timed_event(NULL, + timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), + "oplock_timeout_handler", + oplock_timeout_handler, fsp); + + if (fsp->oplock_timeout == NULL) { + DEBUG(0, ("Could not add oplock timeout handler\n")); + } +} + +/******************************************************************* + This handles the case of a write triggering a break to none + message on a level2 oplock. + When we get this message we may be in any of three states : + NO_OPLOCK, LEVEL_II, FAKE_LEVEL2. We only send a message to + the client for LEVEL2. +*******************************************************************/ + +static void process_oplock_async_level2_break_message(int msg_type, struct process_id src, + void *buf, size_t len) +{ + struct share_mode_entry msg; + files_struct *fsp; + char *break_msg; + BOOL break_to_level2 = False; + BOOL sign_state; + + if (buf == NULL) { + DEBUG(0, ("Got NULL buffer\n")); + return; + } + + if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { + DEBUG(0, ("Got invalid msg len %d\n", (int)len)); + return; + } + + /* De-linearize incoming message. */ + message_to_share_mode_entry(&msg, buf); + + DEBUG(10, ("Got oplock async level 2 break message from pid %d: 0x%x/%.0f/%d\n", + (int)procid_to_pid(&src), (unsigned int)msg.dev, (double)msg.inode, + (int)msg.share_file_id)); + + fsp = initial_break_processing(msg.dev, msg.inode, + msg.share_file_id); + + if (fsp == NULL) { + /* We hit a race here. Break messages are sent, and before we + * get to process this message, we have closed the file. + * No need to reply as this is an async message. */ + DEBUG(3, ("process_oplock_async_level2_break_message: Did not find fsp, ignoring\n")); + return; + } + + if (fsp->oplock_type == NO_OPLOCK) { + /* We already got a "break to none" message and we've handled it. + * just ignore. */ + DEBUG(3, ("process_oplock_async_level2_break_message: already broken to none, ignoring.\n")); + return; + } + + if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { + /* Don't tell the client, just downgrade. */ + DEBUG(3, ("process_oplock_async_level2_break_message: downgrading fake level 2 oplock.\n")); + remove_oplock(fsp); + return; + } + + /* Ensure we're really at level2 state. */ + SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK); + + /* Now send a break to none message to our client. */ + + break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); + if (break_msg == NULL) { + exit_server("Could not talloc break_msg\n"); + } + + /* Need to wait before sending a break message if we sent ourselves this message. */ + if (procid_to_pid(&src) == sys_getpid()) { + wait_before_sending_break(); + } + + /* Save the server smb signing state. */ + sign_state = srv_oplock_set_signing(False); + + show_msg(break_msg); + if (!send_smb(smbd_server_fd(), break_msg)) { + exit_server("oplock_break: send_smb failed."); + } + + /* Restore the sign state to what it was. */ + srv_oplock_set_signing(sign_state); + + talloc_free(break_msg); + + /* Async level2 request, don't send a reply, just remove the oplock. */ + remove_oplock(fsp); +} + +/******************************************************************* + This handles the generic oplock break message from another smbd. +*******************************************************************/ + static void process_oplock_break_message(int msg_type, struct process_id src, void *buf, size_t len) { @@ -408,7 +525,7 @@ static void process_oplock_break_message(int msg_type, struct process_id src, msg.share_file_id); if (fsp == NULL) { - /* We hit race here. Break messages are sent, and before we + /* a We hit race here. Break messages are sent, and before we * get to process this message, we have closed the file. Reply * with 'ok, oplock broken' */ DEBUG(3, ("Did not find fsp\n")); @@ -447,8 +564,7 @@ static void process_oplock_break_message(int msg_type, struct process_id src, return; } - if ((msg_type == MSG_SMB_BREAK_REQUEST) && - (global_client_caps & CAP_LEVEL_II_OPLOCKS) && + if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !koplocks && /* NOTE: we force levelII off for kernel oplocks - * this will change when it is supported */ lp_level2_oplocks(SNUM(fsp->conn))) { @@ -461,7 +577,7 @@ static void process_oplock_break_message(int msg_type, struct process_id src, exit_server("Could not talloc break_msg\n"); } - /* Need to wait before sending a break message to a file of our own */ + /* Need to wait before sending a break message if we sent ourselves this message. */ if (procid_to_pid(&src) == sys_getpid()) { wait_before_sending_break(); } @@ -479,34 +595,20 @@ static void process_oplock_break_message(int msg_type, struct process_id src, talloc_free(break_msg); - if (msg_type == MSG_SMB_BREAK_REQUEST) { - fsp->sent_oplock_break = break_to_level2 ? - LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; - } else { - /* Async level2 request, don't send a reply */ - fsp->sent_oplock_break = ASYNC_LEVEL_II_BREAK_SENT; - } + fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; + msg.pid = src; ADD_TO_ARRAY(NULL, struct share_mode_entry, msg, &fsp->pending_break_messages, &fsp->num_pending_break_messages); - if (fsp->oplock_timeout != NULL) { - DEBUG(0, ("Logic problem -- have an oplock event hanging " - "around\n")); - } - - fsp->oplock_timeout = - add_timed_event(NULL, - timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), - "oplock_timeout_handler", - oplock_timeout_handler, fsp); - - if (fsp->oplock_timeout == NULL) { - DEBUG(0, ("Could not add oplock timeout handler\n")); - } + add_oplock_timeout_handler(fsp); } +/******************************************************************* + This handles the kernel oplock break message. +*******************************************************************/ + static void process_kernel_oplock_break(int msg_type, struct process_id src, void *buf, size_t len) { @@ -570,6 +672,8 @@ static void process_kernel_oplock_break(int msg_type, struct process_id src, talloc_free(break_msg); fsp->sent_oplock_break = BREAK_TO_NONE_SENT; + + add_oplock_timeout_handler(fsp); } void reply_to_oplock_break_requests(files_struct *fsp) @@ -591,6 +695,7 @@ void reply_to_oplock_break_requests(files_struct *fsp) SAFE_FREE(fsp->pending_break_messages); fsp->num_pending_break_messages = 0; if (fsp->oplock_timeout != NULL) { + /* Remove the timed event handler. */ talloc_free(fsp->oplock_timeout); fsp->oplock_timeout = NULL; } @@ -679,29 +784,6 @@ void release_level_2_oplocks_on_change(files_struct *fsp) DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", lck->num_share_modes )); - if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { - /* See if someone else has already downgraded us, then we - don't have to do anything */ - for (i=0; inum_share_modes; i++) { - struct share_mode_entry *e = &lck->share_modes[i]; - - if (!is_valid_share_mode_entry(e)) { - continue; - } - - if ((e->op_type == NO_OPLOCK) && - (e->share_file_id == fsp->file_id) && - (e->dev == fsp->dev) && - (e->inode == fsp->inode) && - (procid_is_me(&e->pid))) { - /* We're done */ - fsp->oplock_type = NO_OPLOCK; - talloc_free(lck); - return; - } - } - } - for(i = 0; i < lck->num_share_modes; i++) { struct share_mode_entry *share_entry = &lck->share_modes[i]; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; @@ -714,7 +796,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) * As there could have been multiple writes waiting at the * lock_share_entry gate we may not be the first to * enter. Hence the state of the op_types in the share mode - * entries may be partly NO_OPLOCK and partly LEVEL_II + * entries may be partly NO_OPLOCK and partly LEVEL_II or FAKE_LEVEL_II * oplock. It will do no harm to re-send break messages to * those smbd's that are still waiting their turn to remove * their LEVEL_II state, and also no harm to ignore existing @@ -725,8 +807,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) "share_entry[%i]->op_type == %d\n", i, share_entry->op_type )); - if ((share_entry->op_type == NO_OPLOCK) || - (share_entry->op_type == FAKE_LEVEL_II_OPLOCK)) { + if (share_entry->op_type == NO_OPLOCK) { continue; } @@ -747,7 +828,9 @@ void release_level_2_oplocks_on_change(files_struct *fsp) unbecome_root(); } - remove_all_share_oplocks(lck, fsp); + /* We let the message receivers handle removing the oplock state + in the share mode lock db. */ + talloc_free(lck); } @@ -795,12 +878,12 @@ void message_to_share_mode_entry(struct share_mode_entry *e, char *msg) BOOL init_oplocks(void) { - DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n")); + DEBUG(3,("open_oplock_ipc: initializing messages.\n")); message_register(MSG_SMB_BREAK_REQUEST, process_oplock_break_message); message_register(MSG_SMB_ASYNC_LEVEL2_BREAK, - process_oplock_break_message); + process_oplock_async_level2_break_message); message_register(MSG_SMB_BREAK_RESPONSE, process_oplock_break_response); message_register(MSG_SMB_KERNEL_BREAK, -- cgit From b7877966d9d2fd140397264f49163120fbd41dfa Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 28 Jan 2006 11:30:43 +0000 Subject: r13202: Fix the build for --with-aio-support. Sorry. Jeremy, configure.in decides whether aio support works quite early in the sequence of checks. Wouldn't it be better to only use aio support if really all necessary functions actually are around? Volker --- source/configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/configure.in b/source/configure.in index 44517ae6eab..7079bf7437a 100644 --- a/source/configure.in +++ b/source/configure.in @@ -4530,8 +4530,8 @@ AC_ARG_WITH(aio-support, AC_MSG_RESULT(yes) case "$host_os" in *) - AC_CHECK_LIB(rt,aio_read,[AIO_LIBS="$AIO_LIBS -lrt"]) - AC_CHECK_LIB(aio,aio_read,[AIO_LIBS="$AIO_LIBS -laio"]) + AC_CHECK_LIB(rt,aio_read,[AIO_LIBS="$LIBS -lrt"]) + AC_CHECK_LIB(aio,aio_read,[AIO_LIBS="$LIBS -laio"]) AC_CACHE_CHECK([for asynchronous io support],samba_cv_HAVE_AIO,[ aio_LIBS=$LIBS LIBS=$AIO_LIBS -- cgit From 78f251ea3b7476d59329380e70f54410009462c0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 28 Jan 2006 17:08:24 +0000 Subject: r13209: Make smbpasswd -a work again if passdb did not exist. Volker --- source/passdb/pdb_tdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index 164ec722998..370c8adc7dc 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -423,6 +423,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT if ((pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT|O_RDWR )) != NULL) { DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n", tdb_state->tdbsam_location)); + tdb_close(pwd_tdb); } else { DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) does not exist. Couldn't create new one. Error was: %s\n", tdb_state->tdbsam_location, strerror(errno))); -- cgit From 6c1e874935c285a278ae18351b4bde309ba32bca Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 28 Jan 2006 22:49:25 +0000 Subject: r13211: Fix remote password changing if password must change is set The problem was that the ntlmssp bind silently failed in that case, we have to do it anonymously. Or does anybody have a better idea? Give a better error message if something else is wrong with the account. Volker --- source/libsmb/passchange.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c index b104a4678d9..8b811b06ead 100644 --- a/source/libsmb/passchange.c +++ b/source/libsmb/passchange.c @@ -34,6 +34,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, struct in_addr ip; NTSTATUS result; + BOOL pass_must_change = False; *err_str = '\0'; @@ -73,6 +74,28 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ if (!cli_session_setup(&cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, "")) { + + result = cli_nt_error(&cli); + + if (!NT_STATUS_IS_OK(result)) { + + /* Password must change is the only valid error + * condition here from where we can proceed, the rest + * like account locked out or logon failure will lead + * to errors later anyway */ + + if (!NT_STATUS_EQUAL(result, + NT_STATUS_PASSWORD_MUST_CHANGE)) { + slprintf(err_str, err_str_len-1, "Could not " + "connect to machine %s: %s\n", + remote_machine, cli_errstr(&cli)); + cli_shutdown(&cli); + return False; + } + + pass_must_change = True; + } + /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... @@ -100,13 +123,25 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, /* Try not to give the password away too easily */ - pipe_hnd = cli_rpc_pipe_open_ntlmssp(&cli, + if (!pass_must_change) { + pipe_hnd = cli_rpc_pipe_open_ntlmssp(&cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY, "", /* what domain... ? */ user_name, old_passwd, &result); + } else { + /* + * If the user password must be changed the ntlmssp bind will + * fail the same way as the session setup above did. The + * difference ist that with a pipe bind we don't get a good + * error message, the result will be that the rpc call below + * will just fail. So we do it anonymously, there's no other + * way. + */ + pipe_hnd = cli_rpc_pipe_open_noauth(&cli, PI_SAMR, &result); + } if (!pipe_hnd) { if (lp_client_lanman_auth()) { -- cgit From 8e40f54fbc0f18732b98730c16022923b37c65b7 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 28 Jan 2006 22:53:04 +0000 Subject: r13212: r12414@cabra: derrell | 2006-01-28 17:52:17 -0500 lp_load() could not be called multiple times to modify parameter settings based on reading from multiple configuration settings. Each time, it initialized all of the settings back to their defaults before reading the specified configuration file. This patch adds a parameter to lp_load() specifying whether the settings should be initialized. It does, however, still force the settings to be initialized the first time, even if the request was to not initialize them. (Not doing so could wreak havoc due to uninitialized values.) --- source/client/client.c | 2 +- source/client/smbctool.c | 2 +- source/client/smbmount.c | 2 +- source/client/smbspool.c | 2 +- source/libsmb/libsmbclient.c | 6 +++--- source/nmbd/nmbd.c | 2 +- source/nsswitch/wbinfo.c | 2 +- source/nsswitch/winbindd.c | 2 +- source/nsswitch/wins.c | 2 +- source/pam_smbpass/support.c | 2 +- source/param/loadparm.c | 17 +++++++++++++---- source/python/py_common.c | 2 +- source/rpcclient/rpcclient.c | 2 +- source/smbd/server.c | 2 +- source/smbwrapper/smbw.c | 2 +- source/torture/locktest.c | 2 +- source/torture/locktest2.c | 2 +- source/torture/masktest.c | 2 +- source/torture/msgtest.c | 2 +- source/torture/rpctorture.c | 2 +- source/torture/t_push_ucs2.c | 2 +- source/torture/t_strcmp.c | 2 +- source/torture/t_strstr.c | 2 +- source/torture/torture.c | 2 +- source/torture/vfstest.c | 4 ++-- source/utils/eventlogadm.c | 2 +- source/utils/net.c | 2 +- source/utils/nmblookup.c | 2 +- source/utils/ntlm_auth.c | 2 +- source/utils/pdbedit.c | 2 +- source/utils/smbcacls.c | 2 +- source/utils/smbcontrol.c | 2 +- source/utils/smbcquotas.c | 2 +- source/utils/smbfilter.c | 2 +- source/utils/smbpasswd.c | 2 +- source/utils/smbtree.c | 2 +- source/utils/smbw_sample.c | 2 +- source/utils/status.c | 2 +- source/utils/testparm.c | 2 +- source/web/swat.c | 2 +- source/wrepld/server.c | 2 +- 41 files changed, 56 insertions(+), 47 deletions(-) diff --git a/source/client/client.c b/source/client/client.c index 7ac64970f81..403074b22b8 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -3449,7 +3449,7 @@ static int do_message_op(void) if ( override_logfile ) setup_logging( lp_logfile(), False ); - if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", argv[0], dyn_CONFIGFILE); } diff --git a/source/client/smbctool.c b/source/client/smbctool.c index db938dd8096..439345ca6de 100644 --- a/source/client/smbctool.c +++ b/source/client/smbctool.c @@ -3654,7 +3654,7 @@ static int do_message_op(void) if ( override_logfile ) setup_logging( lp_logfile(), False ); - if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", argv[0], dyn_CONFIGFILE); } diff --git a/source/client/smbmount.c b/source/client/smbmount.c index d8254ef23a7..21882ab2e96 100644 --- a/source/client/smbmount.c +++ b/source/client/smbmount.c @@ -910,7 +910,7 @@ static void parse_mount_smb(int argc, char **argv) pstrcpy(username,getenv("LOGNAME")); } - if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); } diff --git a/source/client/smbspool.c b/source/client/smbspool.c index 7fe918413d5..d7a02b76f93 100644 --- a/source/client/smbspool.c +++ b/source/client/smbspool.c @@ -214,7 +214,7 @@ static int smb_print(struct cli_state *, char *, FILE *); in_client = True; /* Make sure that we tell lp_load we are */ - if (!lp_load(dyn_CONFIGFILE, True, False, False)) + if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) { fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); return (1); diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index 51f94e42e37..fda619c5292 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -6025,7 +6025,7 @@ smbc_init_context(SMBCCTX *context) home = getenv("HOME"); if (home) { slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home); - if (lp_load(conf, True, False, False)) { + if (lp_load(conf, True, False, False, True)) { conf_loaded = True; } else { DEBUG(5, ("Could not load config file: %s\n", @@ -6041,7 +6041,7 @@ smbc_init_context(SMBCCTX *context) * defaults ... */ - if (!lp_load(dyn_CONFIGFILE, True, False, False)) { + if (!lp_load(dyn_CONFIGFILE, True, False, False, False)) { DEBUG(5, ("Could not load config file: %s\n", dyn_CONFIGFILE)); } else if (home) { @@ -6052,7 +6052,7 @@ smbc_init_context(SMBCCTX *context) */ slprintf(conf, sizeof(conf), "%s/.smb/smb.conf.append", home); - if (!lp_load(conf, True, False, False)) { + if (!lp_load(conf, True, False, False, False)) { DEBUG(10, ("Could not append config file: " "%s\n", diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index ea7e9a5288f..f69cc32ff60 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -291,7 +291,7 @@ static BOOL reload_nmbd_services(BOOL test) if ( test && !lp_file_list_changed() ) return(True); - ret = lp_load( dyn_CONFIGFILE, True , False, False); + ret = lp_load( dyn_CONFIGFILE, True , False, False, True); /* perhaps the config filename is now set */ if ( !test ) { diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index f3819b6f519..b7c3b0a98c5 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -1024,7 +1024,7 @@ int main(int argc, char **argv) /* Samba client initialisation */ load_case_tables(); - if (!lp_load(dyn_CONFIGFILE, True, False, False)) { + if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) { d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n", dyn_CONFIGFILE, strerror(errno)); exit(1); diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index e9b9ed42c4f..bbcf2b5e887 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -47,7 +47,7 @@ static BOOL reload_services_file(void) } reopen_logs(); - ret = lp_load(dyn_CONFIGFILE,False,False,True); + ret = lp_load(dyn_CONFIGFILE,False,False,True,True); reopen_logs(); load_interfaces(); diff --git a/source/nsswitch/wins.c b/source/nsswitch/wins.c index ac5b0f11572..f871a53982e 100644 --- a/source/nsswitch/wins.c +++ b/source/nsswitch/wins.c @@ -80,7 +80,7 @@ static void nss_wins_init(void) TimeInit(); setup_logging("nss_wins",False); - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); } diff --git a/source/pam_smbpass/support.c b/source/pam_smbpass/support.c index 82d51103d26..3f2c6388160 100644 --- a/source/pam_smbpass/support.c +++ b/source/pam_smbpass/support.c @@ -167,7 +167,7 @@ int set_ctrl( int flags, int argc, const char **argv ) /* Read some options from the Samba config. Can be overridden by the PAM config. */ - if(lp_load(service_file,True,False,False) == False) { + if(lp_load(service_file,True,False,False,True) == False) { _log_err( LOG_ERR, "Error loading service file %s", service_file ); } diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 83a5b2fc3cf..a2aa851b095 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -1354,11 +1354,17 @@ static void init_printer_values(service *pService) Initialise the global parameter structure. ***************************************************************************/ -static void init_globals(void) +static void init_globals(BOOL first_time_only) { static BOOL done_init = False; pstring s; + /* If requested to initialize only once and we've already done it... */ + if (first_time_only && done_init) { + /* ... then we have nothing more to do */ + return; + } + if (!done_init) { int i; @@ -4188,8 +4194,11 @@ static void set_allowed_client_auth(void) False on failure. ***************************************************************************/ -BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults, - BOOL add_ipc) +BOOL lp_load(const char *pszFname, + BOOL global_only, + BOOL save_defaults, + BOOL add_ipc, + BOOL initialize_globals) { pstring n2; BOOL bRetval; @@ -4208,7 +4217,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults, bInGlobalSection = True; bGlobalOnly = global_only; - init_globals(); + init_globals(! initialize_globals); debug_init(); if (save_defaults) { diff --git a/source/python/py_common.c b/source/python/py_common.c index 66f35759c3d..70d478b9797 100644 --- a/source/python/py_common.c +++ b/source/python/py_common.c @@ -47,7 +47,7 @@ void py_samba_init(void) /* Load configuration file */ - if (!lp_load(dyn_CONFIGFILE, True, False, False)) + if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE); /* Misc other stuff */ diff --git a/source/rpcclient/rpcclient.c b/source/rpcclient/rpcclient.c index 5bca67d7a63..5e66b182630 100644 --- a/source/rpcclient/rpcclient.c +++ b/source/rpcclient/rpcclient.c @@ -757,7 +757,7 @@ out_free: /* Load smb.conf file */ - if (!lp_load(dyn_CONFIGFILE,True,False,False)) + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE); /* diff --git a/source/smbd/server.c b/source/smbd/server.c index 620bf3ebbdd..3e970ec16c2 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -529,7 +529,7 @@ BOOL reload_services(BOOL test) lp_killunused(conn_snum_used); - ret = lp_load(dyn_CONFIGFILE, False, False, True); + ret = lp_load(dyn_CONFIGFILE, False, False, True, True); reload_printers(); diff --git a/source/smbwrapper/smbw.c b/source/smbwrapper/smbw.c index edcc7a5c2f9..d4a5b51af4e 100644 --- a/source/smbwrapper/smbw.c +++ b/source/smbwrapper/smbw.c @@ -76,7 +76,7 @@ void smbw_init(void) pstrcpy(dyn_CONFIGFILE, p); } - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); if (!init_names()) exit(1); diff --git a/source/torture/locktest.c b/source/torture/locktest.c index c8336ebaf66..913df885bae 100644 --- a/source/torture/locktest.c +++ b/source/torture/locktest.c @@ -586,7 +586,7 @@ static void usage(void) argc -= NSERVERS; argv += NSERVERS; - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); if (getenv("USER")) { diff --git a/source/torture/locktest2.c b/source/torture/locktest2.c index fc180bfafe2..519acebe8e8 100644 --- a/source/torture/locktest2.c +++ b/source/torture/locktest2.c @@ -498,7 +498,7 @@ static void usage(void) argc -= 4; argv += 4; - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); if (getenv("USER")) { diff --git a/source/torture/masktest.c b/source/torture/masktest.c index 07bfe691217..ffc9a20e71c 100644 --- a/source/torture/masktest.c +++ b/source/torture/masktest.c @@ -454,7 +454,7 @@ static void usage(void) argc -= 1; argv += 1; - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); if (getenv("USER")) { diff --git a/source/torture/msgtest.c b/source/torture/msgtest.c index d691ab32f1d..f7c47ddbbf8 100644 --- a/source/torture/msgtest.c +++ b/source/torture/msgtest.c @@ -41,7 +41,7 @@ void pong_message(int msg_type, struct process_id src, void *buf, size_t len) setup_logging(argv[0],True); - lp_load(dyn_CONFIGFILE,False,False,False); + lp_load(dyn_CONFIGFILE,False,False,False,True); message_init(); diff --git a/source/torture/rpctorture.c b/source/torture/rpctorture.c index 28067c1a0ae..d69cc8eb8df 100644 --- a/source/torture/rpctorture.c +++ b/source/torture/rpctorture.c @@ -242,7 +242,7 @@ enum client_action *term_code = 0; #endif /* KANJI */ - if (!lp_load(dyn_CONFIGFILE,True, False, False)) + if (!lp_load(dyn_CONFIGFILE,True, False, False, True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); } diff --git a/source/torture/t_push_ucs2.c b/source/torture/t_push_ucs2.c index 8bfc6f7ad9e..8d327acfa56 100644 --- a/source/torture/t_push_ucs2.c +++ b/source/torture/t_push_ucs2.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) int count = 1; /* Needed to initialize character set */ - lp_load("/dev/null", True, False, False); + lp_load("/dev/null", True, False, False, True); if (argc < 2) { fprintf(stderr, "usage: %s STRING1 [COUNT]\n" diff --git a/source/torture/t_strcmp.c b/source/torture/t_strcmp.c index bc8640ee550..318423b8be0 100644 --- a/source/torture/t_strcmp.c +++ b/source/torture/t_strcmp.c @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) int iters = 1; /* Needed to initialize character set */ - lp_load("/dev/null", True, False, False); + lp_load("/dev/null", True, False, False, True); if (argc < 3) { fprintf(stderr, "usage: %s STRING1 STRING2 [ITERS]\n" diff --git a/source/torture/t_strstr.c b/source/torture/t_strstr.c index 7b928fb26be..49180b219f7 100644 --- a/source/torture/t_strstr.c +++ b/source/torture/t_strstr.c @@ -14,7 +14,7 @@ int main(int argc, char *argv[]) const char *ret = NULL; /* Needed to initialize character set */ - lp_load("/dev/null", True, False, False); + lp_load("/dev/null", True, False, False, True); if (argc < 3) { fprintf(stderr, "usage: %s STRING1 STRING2 [ITERS]\n" diff --git a/source/torture/torture.c b/source/torture/torture.c index e995c3cc58a..0b3bfc18f4a 100644 --- a/source/torture/torture.c +++ b/source/torture/torture.c @@ -4916,7 +4916,7 @@ static void usage(void) load_case_tables(); - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); if (argc < 2) { diff --git a/source/torture/vfstest.c b/source/torture/vfstest.c index 1914a4acb50..023e656c672 100644 --- a/source/torture/vfstest.c +++ b/source/torture/vfstest.c @@ -113,7 +113,7 @@ static NTSTATUS cmd_conf(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } - if (!lp_load(argv[1], False, True, False)) { + if (!lp_load(argv[1], False, True, False, True)) { printf("Error loading \"%s\"\n", argv[1]); return NT_STATUS_OK; } @@ -448,7 +448,7 @@ BOOL reload_services(BOOL test) lp_killunused(conn_snum_used); - ret = lp_load(dyn_CONFIGFILE, False, False, True); + ret = lp_load(dyn_CONFIGFILE, False, False, True, True); /* perhaps the config filename is now set */ if (!test) diff --git a/source/utils/eventlogadm.c b/source/utils/eventlogadm.c index eef7cde3771..8cf79fcf14b 100644 --- a/source/utils/eventlogadm.c +++ b/source/utils/eventlogadm.c @@ -170,7 +170,7 @@ int main( int argc, char *argv[] ) opt_debug = 0; /* todo set this from getopts */ - lp_load( dyn_CONFIGFILE, True, False, False ); + lp_load( dyn_CONFIGFILE, True, False, False, True); exename = argv[0]; srcname = NULL; diff --git a/source/utils/net.c b/source/utils/net.c index a2a9ac6a391..25e10c6a316 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -825,7 +825,7 @@ static struct functable net_func[] = { * set by cmdline arg or remain default (0) */ AllowDebugChange = False; - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); argv_new = (const char **)poptGetArgs(pc); diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c index e88d7862901..12ac1beb7b1 100644 --- a/source/utils/nmblookup.c +++ b/source/utils/nmblookup.c @@ -248,7 +248,7 @@ int main(int argc,char *argv[]) exit(1); } - if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); } diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c index 65dbfb71650..4759aec0ccf 100644 --- a/source/utils/ntlm_auth.c +++ b/source/utils/ntlm_auth.c @@ -1758,7 +1758,7 @@ enum { /* Samba client initialisation */ - if (!lp_load(dyn_CONFIGFILE, True, False, False)) { + if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) { d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n", dyn_CONFIGFILE, strerror(errno)); exit(1); diff --git a/source/utils/pdbedit.c b/source/utils/pdbedit.c index 53d3b17d064..f41bbb8caaf 100644 --- a/source/utils/pdbedit.c +++ b/source/utils/pdbedit.c @@ -795,7 +795,7 @@ int main (int argc, char **argv) if (user_name == NULL) user_name = poptGetArg(pc); - if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); exit(1); } diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c index cbbd7adaab3..26362c6270a 100644 --- a/source/utils/smbcacls.c +++ b/source/utils/smbcacls.c @@ -830,7 +830,7 @@ static struct cli_state *connect_one(const char *share) setlinebuf(stdout); - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); pc = poptGetContext("smbcacls", argc, argv, long_options, 0); diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c index b8f7c2f2b55..a4d2766b132 100644 --- a/source/utils/smbcontrol.c +++ b/source/utils/smbcontrol.c @@ -827,7 +827,7 @@ int main(int argc, const char **argv) if (argc == 1) usage(&pc); - lp_load(dyn_CONFIGFILE,False,False,False); + lp_load(dyn_CONFIGFILE,False,False,False,True); /* Need to invert sense of return code -- samba * routines mostly return True==1 for success, but diff --git a/source/utils/smbcquotas.c b/source/utils/smbcquotas.c index f8e33131555..b1a14685f5e 100644 --- a/source/utils/smbcquotas.c +++ b/source/utils/smbcquotas.c @@ -435,7 +435,7 @@ FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" }, fault_setup(NULL); - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); pc = poptGetContext("smbcquotas", argc, argv, long_options, 0); diff --git a/source/utils/smbfilter.c b/source/utils/smbfilter.c index 3665647905d..97d22230c4b 100644 --- a/source/utils/smbfilter.c +++ b/source/utils/smbfilter.c @@ -236,7 +236,7 @@ int main(int argc, char *argv[]) netbiosname = argv[2]; } - if (!lp_load(configfile,True,False,False)) { + if (!lp_load(configfile,True,False,False,True)) { d_printf("Unable to load config file\n"); } diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c index 29189c5febd..7eb11137d70 100644 --- a/source/utils/smbpasswd.c +++ b/source/utils/smbpasswd.c @@ -187,7 +187,7 @@ static int process_options(int argc, char **argv, int local_flags) usage(); } - if (!lp_load(configfile,True,False,False)) { + if (!lp_load(configfile,True,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); exit(1); diff --git a/source/utils/smbtree.c b/source/utils/smbtree.c index 3755b7f8e55..853a46f379e 100644 --- a/source/utils/smbtree.c +++ b/source/utils/smbtree.c @@ -216,7 +216,7 @@ static BOOL print_tree(struct user_auth_info *user_info) while(poptGetNextOpt(pc) != -1); poptFreeContext(pc); - lp_load(dyn_CONFIGFILE,True,False,False); + lp_load(dyn_CONFIGFILE,True,False,False,True); load_interfaces(); /* Parse command line args */ diff --git a/source/utils/smbw_sample.c b/source/utils/smbw_sample.c index 5cd792df7a2..ba78eb22fc7 100644 --- a/source/utils/smbw_sample.c +++ b/source/utils/smbw_sample.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) extern int optind; char *path; - lp_load(dyn_CONFIGFILE,1,0,0); + lp_load(dyn_CONFIGFILE,1,0,0,1); smbw_setup_shared(); while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) { diff --git a/source/utils/status.c b/source/utils/status.c index eeaf83d1772..2aed68be897 100644 --- a/source/utils/status.c +++ b/source/utils/status.c @@ -648,7 +648,7 @@ static int traverse_sessionid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, vo d_printf("using configfile = %s\n", dyn_CONFIGFILE); } - if (!lp_load(dyn_CONFIGFILE,False,False,False)) { + if (!lp_load(dyn_CONFIGFILE,False,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); return (-1); } diff --git a/source/utils/testparm.c b/source/utils/testparm.c index 11ce960e557..8b9ff4710e0 100644 --- a/source/utils/testparm.c +++ b/source/utils/testparm.c @@ -266,7 +266,7 @@ via the %%o substitution. With encrypted passwords this is not possible.\n", lp_ fprintf(stderr,"Load smb config files from %s\n",config_file); - if (!lp_load(config_file,False,True,False)) { + if (!lp_load(config_file,False,True,False,True)) { fprintf(stderr,"Error loading services.\n"); return(1); } diff --git a/source/web/swat.c b/source/web/swat.c index 372d473bdb5..63253e41c40 100644 --- a/source/web/swat.c +++ b/source/web/swat.c @@ -422,7 +422,7 @@ static void show_parameters(int snum, int allparameters, unsigned int parm_filte static BOOL load_config(BOOL save_def) { lp_resetnumservices(); - return lp_load(dyn_CONFIGFILE,False,save_def,False); + return lp_load(dyn_CONFIGFILE,False,save_def,False,True); } /**************************************************************************** diff --git a/source/wrepld/server.c b/source/wrepld/server.c index 5ac78a24745..754bad01b0d 100644 --- a/source/wrepld/server.c +++ b/source/wrepld/server.c @@ -64,7 +64,7 @@ BOOL reload_services(BOOL test) if (test && !lp_file_list_changed()) return(True); - ret = lp_load(dyn_CONFIGFILE,False,False,True); + ret = lp_load(dyn_CONFIGFILE,False,False,True,True); /* perhaps the config filename is now set */ -- cgit From 783571356a332e82d2674bb33d568fdf69469127 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 29 Jan 2006 00:11:34 +0000 Subject: r13214: r12420@cabra: derrell | 2006-01-28 19:10:58 -0500 This should fix bug #3446. - The authentication domain provided an an SMB URL was being ignored. This patch fixes that. - There were a number of places where string copies were not being confirmed to be properly null-terminated. Now, all string copies in libsmbclient.c are properly null-terminated. --- source/libsmb/libsmbclient.c | 101 ++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index fda619c5292..e992cbbfc45 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -181,7 +181,8 @@ smbc_urldecode(char *dest, char * src, size_t max_dest_len) *p = '\0'; - strncpy(dest, temp, max_dest_len); + strncpy(dest, temp, max_dest_len - 1); + dest[max_dest_len - 1] = '\0'; return err_count; } @@ -268,6 +269,7 @@ static const char *smbc_prefix = "smb:"; static int smbc_parse_path(SMBCCTX *context, const char *fname, + char *workgroup, int workgroup_len, char *server, int server_len, char *share, int share_len, char *path, int path_len, @@ -282,6 +284,16 @@ smbc_parse_path(SMBCCTX *context, int len; server[0] = share[0] = path[0] = user[0] = password[0] = (char)0; + + /* + * Assume we wont find an authentication domain to parse, so default + * to the workgroup in the provided context. + */ + if (workgroup != NULL) { + strncpy(workgroup, context->workgroup, workgroup_len - 1); + workgroup[workgroup_len - 1] = '\0'; + } + if (options != NULL && options_len > 0) { options[0] = (char)0; } @@ -328,6 +340,7 @@ smbc_parse_path(SMBCCTX *context, ((strlen(context->workgroup) < 16) ? strlen(context->workgroup) : 16)); + server[server_len - 1] = '\0'; return 0; } @@ -369,11 +382,20 @@ smbc_parse_path(SMBCCTX *context, } - if (username[0]) - strncpy(user, username, user_len); /* FIXME, domain */ + if (domain[0] && workgroup) { + strncpy(workgroup, domain, workgroup_len - 1); + workgroup[workgroup_len - 1] = '\0'; + } - if (passwd[0]) - strncpy(password, passwd, password_len); + if (username[0]) { + strncpy(user, username, user_len - 1); + user[user_len - 1] = '\0'; + } + + if (passwd[0]) { + strncpy(password, passwd, password_len - 1); + password[password_len - 1] = '\0'; + } } @@ -1001,6 +1023,7 @@ smbc_open_ctx(SMBCCTX *context, } if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -1013,8 +1036,6 @@ smbc_open_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -1208,6 +1229,7 @@ smbc_read_ctx(SMBCCTX *context, /*d_printf(">>>read: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -1288,6 +1310,7 @@ smbc_write_ctx(SMBCCTX *context, /*d_printf(">>>write: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -1359,6 +1382,7 @@ smbc_close_ctx(SMBCCTX *context, /*d_printf(">>>close: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -1645,6 +1669,7 @@ smbc_unlink_ctx(SMBCCTX *context, } if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -1657,8 +1682,6 @@ smbc_unlink_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -1762,6 +1785,7 @@ smbc_rename_ctx(SMBCCTX *ocontext, DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); smbc_parse_path(ocontext, oname, + workgroup, sizeof(workgroup), server1, sizeof(server1), share1, sizeof(share1), path1, sizeof(path1), @@ -1772,6 +1796,7 @@ smbc_rename_ctx(SMBCCTX *ocontext, if (user1[0] == (char)0) fstrcpy(user1, ocontext->user); smbc_parse_path(ncontext, nname, + NULL, 0, server2, sizeof(server2), share2, sizeof(share2), path2, sizeof(path2), @@ -1791,8 +1816,6 @@ smbc_rename_ctx(SMBCCTX *ocontext, } - fstrcpy(workgroup, ocontext->workgroup); - srv = smbc_server(ocontext, True, server1, share1, workgroup, user1, password1); if (!srv) { @@ -1891,6 +1914,7 @@ smbc_lseek_ctx(SMBCCTX *context, case SEEK_END: /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -2049,6 +2073,7 @@ smbc_stat_ctx(SMBCCTX *context, DEBUG(4, ("smbc_stat(%s)\n", fname)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -2061,8 +2086,6 @@ smbc_stat_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -2137,6 +2160,7 @@ smbc_fstat_ctx(SMBCCTX *context, /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -2270,8 +2294,12 @@ add_dirent(SMBCFILE *dir, dirent->commentlen = comment_len; dirent->dirlen = size; + /* + * dirent->namelen + 1 includes the null (no null termination needed) + * Ditto for dirent->commentlen. + * The space for the two null bytes was allocated. + */ strncpy(dirent->name, (name?name:""), dirent->namelen + 1); - dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); @@ -2510,6 +2538,7 @@ smbc_opendir_ctx(SMBCCTX *context, } if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -2534,8 +2563,6 @@ smbc_opendir_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - pstrcpy(workgroup, context->workgroup); - dir = SMB_MALLOC_P(SMBCFILE); if (!dir) { @@ -2934,14 +2961,8 @@ smbc_readdir_internal(SMBCCTX * context, dest->comment = dest->name + dest->namelen + 1; /* Copy the comment */ - strncpy(dest->comment, src->comment, max_namebuf_len); - - /* Ensure the comment is null terminated */ - if (max_namebuf_len > src->commentlen) { - dest->comment[src->commentlen] = '\0'; - } else { - dest->comment[max_namebuf_len - 1] = '\0'; - } + strncpy(dest->comment, src->comment, max_namebuf_len - 1); + dest->comment[max_namebuf_len - 1] = '\0'; /* Save other fields */ dest->smbc_type = src->smbc_type; @@ -3156,6 +3177,7 @@ smbc_mkdir_ctx(SMBCCTX *context, DEBUG(4, ("smbc_mkdir(%s)\n", fname)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -3168,8 +3190,6 @@ smbc_mkdir_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -3253,6 +3273,7 @@ smbc_rmdir_ctx(SMBCCTX *context, DEBUG(4, ("smbc_rmdir(%s)\n", fname)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -3266,8 +3287,6 @@ smbc_rmdir_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -3507,6 +3526,7 @@ smbc_chmod_ctx(SMBCCTX *context, DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -3519,8 +3539,6 @@ smbc_chmod_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -3586,13 +3604,13 @@ smbc_utimes_ctx(SMBCCTX *context, char atimebuf[32]; char mtimebuf[32]; - strncpy(atimebuf, ctime(&a_time), sizeof(atimebuf)); + strncpy(atimebuf, ctime(&a_time), sizeof(atimebuf) - 1); atimebuf[sizeof(atimebuf) - 1] = '\0'; if ((p = strchr(atimebuf, '\n')) != NULL) { *p = '\0'; } - strncpy(mtimebuf, ctime(&m_time), sizeof(mtimebuf)); + strncpy(mtimebuf, ctime(&m_time), sizeof(mtimebuf) - 1); mtimebuf[sizeof(mtimebuf) - 1] = '\0'; if ((p = strchr(mtimebuf, '\n')) != NULL) { *p = '\0'; @@ -3603,6 +3621,7 @@ smbc_utimes_ctx(SMBCCTX *context, } if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -3615,8 +3634,6 @@ smbc_utimes_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -4999,6 +5016,7 @@ smbc_setxattr_ctx(SMBCCTX *context, fname, name, (int) size, (const char*)value)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5011,8 +5029,6 @@ smbc_setxattr_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); if (!srv) { @@ -5267,6 +5283,7 @@ smbc_getxattr_ctx(SMBCCTX *context, DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5279,8 +5296,6 @@ smbc_getxattr_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); if (!srv) { @@ -5384,6 +5399,7 @@ smbc_removexattr_ctx(SMBCCTX *context, DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5396,8 +5412,6 @@ smbc_removexattr_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); if (!srv) { @@ -5539,6 +5553,7 @@ smbc_open_print_job_ctx(SMBCCTX *context, DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname)); if (smbc_parse_path(context, fname, + NULL, 0, server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5676,6 +5691,7 @@ smbc_list_print_jobs_ctx(SMBCCTX *context, DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5688,8 +5704,6 @@ smbc_list_print_jobs_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); @@ -5747,6 +5761,7 @@ smbc_unlink_print_job_ctx(SMBCCTX *context, DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); if (smbc_parse_path(context, fname, + workgroup, sizeof(workgroup), server, sizeof(server), share, sizeof(share), path, sizeof(path), @@ -5759,8 +5774,6 @@ smbc_unlink_print_job_ctx(SMBCCTX *context, if (user[0] == (char)0) fstrcpy(user, context->user); - fstrcpy(workgroup, context->workgroup); - srv = smbc_server(context, True, server, share, workgroup, user, password); -- cgit From ee25321fedacff1ab3f5aaccabc9bf2a3d0b836a Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 29 Jan 2006 04:57:42 +0000 Subject: r13216: r12422@cabra: derrell | 2006-01-28 23:57:35 -0500 Fix cli_setpathinfo() to actually do what it's supposed to. Also, get rid of some apparently drug-induced code to deal with create time which isn't being manipulated anyway. --- source/libsmb/clirap.c | 34 +++++++++++++++++----------------- source/libsmb/libsmbclient.c | 33 --------------------------------- 2 files changed, 17 insertions(+), 50 deletions(-) diff --git a/source/libsmb/clirap.c b/source/libsmb/clirap.c index 6716971fe2c..58fa9c8dfff 100644 --- a/source/libsmb/clirap.c +++ b/source/libsmb/clirap.c @@ -471,7 +471,6 @@ BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, char *rparam=NULL, *rdata=NULL; int count=8; BOOL ret; - void (*date_fn)(struct cli_state *, char *buf,int offset,time_t unixdate); char *p; memset(param, 0, sizeof(param)); @@ -480,7 +479,7 @@ BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, p = param; /* Add the information level */ - SSVAL(p, 0, SMB_INFO_STANDARD); + SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION); /* Skip reserved */ p += 6; @@ -492,26 +491,27 @@ BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, p = data; - if (cli->win95) { - date_fn = cli_put_dos_date; - } else { - date_fn = cli_put_dos_date2; - } - - /* Add the create, last access, and modification times */ - (*date_fn)(cli, p, 0, c_time); - (*date_fn)(cli, p, 4, a_time); - (*date_fn)(cli, p, 8, m_time); - p += 12; + /* + * Add the create, last access, modification, and status change times + */ + + /* Don't set create time, at offset 0 */ + p += 8; - /* Skip DataSize and AllocationSize */ + put_long_date(p, a_time); + p += 8; + + put_long_date(p, m_time); + p += 8; + + put_long_date(p, c_time); p += 8; /* Add attributes */ - SSVAL(p, 0, mode); - p += 2; + SIVAL(p, 0, mode); + p += 4; - /* Add EA size (none) */ + /* Add padding */ SIVAL(p, 0, 0); p += 4; diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index e992cbbfc45..44cb43c285e 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -1522,39 +1522,6 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, int fd; int ret; - /* - * Get the create time of the file (if not provided); we'll need it in - * the set call. - */ - if (! srv->no_pathinfo && c_time == 0) { - if (! cli_qpathinfo(&srv->cli, path, - &c_time, NULL, NULL, NULL, NULL)) { - /* qpathinfo not available */ - srv->no_pathinfo = True; - } else { - /* - * We got a creation time. Some OS versions don't - * return a valid create time, though. If we got an - * invalid time, start with the current time instead. - */ - if (c_time == 0 || c_time == (time_t) -1) { - c_time = time(NULL); - } - - /* - * We got a creation time. For sanity sake, since - * there is no POSIX function to set the create time - * of a file, if the existing create time is greater - * than either of access time or modification time, - * set create time to the smallest of those. This - * ensure that the create time of a file is never - * greater than its last access or modification time. - */ - if (c_time > a_time) c_time = a_time; - if (c_time > m_time) c_time = m_time; - } - } - /* * First, try setpathinfo (if qpathinfo succeeded), for it is the * modern function for "new code" to be using, and it works given a -- cgit From 98e520c5f37fe9cbb57728c4b69081868674719a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 29 Jan 2006 18:22:39 +0000 Subject: r13222: Never assume mode_t is of type int. We were trashing the stack on machines that define mode_t as uint16_t --- source/modules/vfs_recycle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/modules/vfs_recycle.c b/source/modules/vfs_recycle.c index 28593f4fbb7..188c50be3e5 100644 --- a/source/modules/vfs_recycle.c +++ b/source/modules/vfs_recycle.c @@ -166,13 +166,13 @@ static int recycle_maxsize(vfs_handle_struct *handle) static mode_t recycle_directory_mode(vfs_handle_struct *handle) { - mode_t dirmode; + int dirmode; const char *buff; buff = lp_parm_const_string(SNUM(handle->conn), "recycle", "directory_mode", NULL); if (buff != NULL ) { - sscanf(buff, "%o", (int *)&dirmode); + sscanf(buff, "%o", &dirmode); } else { dirmode=S_IRUSR | S_IWUSR | S_IXUSR; } -- cgit From a256fc02e6041e8877d10ec0f3ab882282d88ee4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 29 Jan 2006 18:43:52 +0000 Subject: r13224: better to cast the return too --- source/modules/vfs_recycle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/modules/vfs_recycle.c b/source/modules/vfs_recycle.c index 188c50be3e5..7b2b15171e4 100644 --- a/source/modules/vfs_recycle.c +++ b/source/modules/vfs_recycle.c @@ -178,7 +178,7 @@ static mode_t recycle_directory_mode(vfs_handle_struct *handle) } DEBUG(10, ("recycle: directory_mode = %o\n", dirmode)); - return dirmode; + return (mode_t)dirmode; } static BOOL recycle_directory_exist(vfs_handle_struct *handle, const char *dname) -- cgit From 17309c0bd090ecf6a07198ea1ddba439a3d12615 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 30 Jan 2006 13:32:41 +0000 Subject: r13229: * fix bad comparison caught by the AIX compiler in wbinfo code * update output from mkversion.sh to include the SAMBA_VENDOR_PATCH --- source/nsswitch/wbinfo.c | 6 +++--- source/script/mkversion.sh | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index b7c3b0a98c5..793a05f1790 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -47,7 +47,7 @@ static char winbind_separator_int(BOOL strict) NSS_STATUS_SUCCESS) { d_fprintf(stderr, "could not obtain winbind separator!\n"); if (strict) { - return -1; + return 0; } /* HACK: (this module should not call lp_ funtions) */ return *lp_winbind_separator(); @@ -59,7 +59,7 @@ static char winbind_separator_int(BOOL strict) if (!sep) { d_fprintf(stderr, "winbind separator was NULL!\n"); if (strict) { - return -1; + return 0; } /* HACK: (this module should not call lp_ funtions) */ sep = *lp_winbind_separator(); @@ -1217,7 +1217,7 @@ int main(int argc, char **argv) break; case OPT_SEPARATOR: { const char sep = winbind_separator_int(True); - if (sep == -1) { + if ( !sep ) { goto done; } d_printf("%c\n", sep); diff --git a/source/script/mkversion.sh b/source/script/mkversion.sh index 1ba7cd63699..57840549213 100755 --- a/source/script/mkversion.sh +++ b/source/script/mkversion.sh @@ -102,7 +102,12 @@ echo "#define SAMBA_VERSION_STRING samba_version_string()" >> $OUTPUT_FILE echo "$0: 'include/version.h' created for Samba(\"${SAMBA_VERSION_STRING}\")" if test -n "${SAMBA_VERSION_VENDOR_SUFFIX}";then - echo "$0: with VENDOR_SUFFIX = ${SAMBA_VERSION_VENDOR_SUFFIX}" + echo -n "$0: with VENDOR_SUFFIX = \"" + echo -n ${SAMBA_VERSION_VENDOR_SUFFIX} | sed 's/"//g' + if test -n ${SAMBA_VENDOR_PATCH}; then + echo -n "-${SAMBA_VENDOR_PATCH}" + fi + echo "\"" fi exit 0 -- cgit From b8cde8c16f32724910a7125ee7fd9b074297aefa Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 30 Jan 2006 17:42:42 +0000 Subject: r13231: apparently strncat() is converted to strcat() on RH7.3 and similar systems. Fix the build on those boxes --- source/lib/version.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/lib/version.c b/source/lib/version.c index 3bd8304012c..a20d6500255 100644 --- a/source/lib/version.c +++ b/source/lib/version.c @@ -29,6 +29,7 @@ const char *samba_version_string(void) static fstring samba_version; fstring tmp_version; static BOOL init_samba_version; + size_t remaining; if (init_samba_version) return samba_version; @@ -38,8 +39,9 @@ const char *samba_version_string(void) SAMBA_VERSION_VENDOR_SUFFIX); #ifdef SAMBA_VENDOR_PATCH - fstr_sprintf( tmp_version, "-%d", SAMBA_VENDOR_PATCH ); - fstrcat( samba_version, tmp_version ); + remaining = sizeof(samba_version)-strlen(samba_version); + snprintf( tmp_version, sizeof(tmp_version), "-%d", SAMBA_VENDOR_PATCH ); + strlcat( samba_version, tmp_version, remaining-1 ); #endif init_samba_version = True; -- cgit From 75914c57a3a08880ee30c0fc3137224e5da4e2cc Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 30 Jan 2006 17:47:24 +0000 Subject: r13232: defensive programming in an attempt to prevent crashes due to a PDC rebooting --- source/nsswitch/winbindd_cm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index 6ac2520f44d..2ac984176c6 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/nsswitch/winbindd_cm.c @@ -101,8 +101,8 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password) static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain, fstring dcname, struct in_addr *dc_ip) { - struct winbindd_domain *our_domain; - struct rpc_pipe_client *netlogon_pipe; + struct winbindd_domain *our_domain = NULL; + struct rpc_pipe_client *netlogon_pipe = NULL; NTSTATUS result; TALLOC_CTX *mem_ctx; @@ -1306,7 +1306,9 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, uint8 mach_pwd[16]; uint32 sec_chan_type; const char *account_name; - struct rpc_pipe_client *netlogon_pipe; + struct rpc_pipe_client *netlogon_pipe = NULL; + + *cli = NULL; result = init_dc_connection(domain); if (!NT_STATUS_IS_OK(result)) { -- cgit From ccc2becfa647d7f1a70c721c403d359742cdfcb0 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 30 Jan 2006 18:38:18 +0000 Subject: r13233: build fixes for smbmnt; remove unused variable; ready to ship 3.0.21b now --- source/Makefile.in | 2 +- source/smbd/oplock.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/Makefile.in b/source/Makefile.in index 15d22d8fa59..6c182a6e41a 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -577,7 +577,7 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \ MOUNT_OBJ = client/smbmount.o \ $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ) -MNT_OBJ = client/smbmnt.o $(VERSION_OBJ) $(SNPRINTF_OBJ) +MNT_OBJ = client/smbmnt.o lib/replace.o $(VERSION_OBJ) $(SNPRINTF_OBJ) UMOUNT_OBJ = client/smbumount.o diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 86f5e1a47cf..755bcffc7f7 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -414,7 +414,6 @@ static void process_oplock_async_level2_break_message(int msg_type, struct proce struct share_mode_entry msg; files_struct *fsp; char *break_msg; - BOOL break_to_level2 = False; BOOL sign_state; if (buf == NULL) { -- cgit From fe5f1f373fd7416e9110ba04a085e82589b81017 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 30 Jan 2006 19:23:32 +0000 Subject: r13235: fixing RedHat 7.x packaging --- packaging/RedHat-9/samba.spec.tmpl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packaging/RedHat-9/samba.spec.tmpl b/packaging/RedHat-9/samba.spec.tmpl index b19a8874983..6ea456c3841 100644 --- a/packaging/RedHat-9/samba.spec.tmpl +++ b/packaging/RedHat-9/samba.spec.tmpl @@ -193,16 +193,16 @@ install -m 755 source/bin/libmsrpc.a $RPM_BUILD_ROOT%{prefix}/lib/ install -m 644 source/include/libmsrpc.h $RPM_BUILD_ROOT%{prefix}/include/ # Install the miscellany -install -m755 packaging/RedHat/smbprint $RPM_BUILD_ROOT%{prefix}/bin -install -m755 packaging/RedHat/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb -install -m755 packaging/RedHat/winbind.init $RPM_BUILD_ROOT/etc/rc.d/init.d/winbind -install -m755 packaging/RedHat/smb.init $RPM_BUILD_ROOT%{prefix}/sbin/samba -install -m644 packaging/RedHat/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba -install -m644 packaging/RedHat/smb.conf $RPM_BUILD_ROOT/etc/samba/smb.conf -install -m644 packaging/RedHat/smbusers $RPM_BUILD_ROOT/etc/samba/smbusers -install -m644 packaging/RedHat/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba -install -m644 packaging/RedHat/samba.pamd.stack $RPM_BUILD_ROOT/etc/samba/samba.stack -install -m644 packaging/RedHat/samba.xinetd $RPM_BUILD_ROOT/etc/samba/samba.xinetd +install -m755 packaging/RedHat-9/smbprint $RPM_BUILD_ROOT%{prefix}/bin +install -m755 packaging/RedHat-9/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb +install -m755 packaging/RedHat-9/winbind.init $RPM_BUILD_ROOT/etc/rc.d/init.d/winbind +install -m755 packaging/RedHat-9/smb.init $RPM_BUILD_ROOT%{prefix}/sbin/samba +install -m644 packaging/RedHat-9/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba +install -m644 packaging/RedHat-9/smb.conf $RPM_BUILD_ROOT/etc/samba/smb.conf +install -m644 packaging/RedHat-9/smbusers $RPM_BUILD_ROOT/etc/samba/smbusers +install -m644 packaging/RedHat-9/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba +install -m644 packaging/RedHat-9/samba.pamd.stack $RPM_BUILD_ROOT/etc/samba/samba.stack +install -m644 packaging/RedHat-9/samba.xinetd $RPM_BUILD_ROOT/etc/samba/samba.xinetd echo 127.0.0.1 localhost > $RPM_BUILD_ROOT/etc/samba/lmhosts # Remove "*.old" files -- cgit From 4e70bba467237311b115e98ebba580baee3f236d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Jan 2006 20:20:17 +0000 Subject: r13238: Fix from Qiao Yang to ensure we always update the failed time when we are adding a failed connection. Jeremy. --- source/libsmb/conncache.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/libsmb/conncache.c b/source/libsmb/conncache.c index fe863db422a..2af4d57b804 100644 --- a/source/libsmb/conncache.c +++ b/source/libsmb/conncache.c @@ -105,10 +105,11 @@ void add_failed_connection_entry(const char *domain, const char *server, NTSTATU a domain, but maybe not a specific DC name. */ for (fcc = failed_connection_cache; fcc; fcc = fcc->next) { - if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) ) - { + if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) ) { DEBUG(10, ("add_failed_connection_entry: domain %s (%s) already tried and failed\n", domain, server )); + /* Update the failed time. */ + fcc->lookup_time = time(NULL); return; } } -- cgit From 7978c451bd0f41bc5f342c0508ebd5a3150b69b7 Mon Sep 17 00:00:00 2001 From: Lars Müller Date: Tue, 31 Jan 2006 10:39:45 +0000 Subject: r13257: Fix python build with older python versions (e.g. 2.2.1) like in United Linux 1 (UL) aka SuSE Linux Enterprise Server (SLES) 8. --- source/python/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/python/setup.py b/source/python/setup.py index ffdafd70877..ce417710b30 100755 --- a/source/python/setup.py +++ b/source/python/setup.py @@ -63,9 +63,9 @@ for lib in string.split(samba_libs): next_is_flag = 0; elif lib == "-Wl,-rpath": next_is_path = 1; - elif lib[0:2] in ("-l"): + elif lib[0:2] == ("-l"): libraries.append(lib[2:]) - elif lib[0:8] in ("-pthread"): + elif lib[0:8] == ("-pthread"): pass # Skip linker flags elif lib[0:2] == "-L": library_dirs.append(lib[2:]) -- cgit From eac11281f26fa24ecef0774074dcbf25c3089ffa Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 31 Jan 2006 18:34:51 +0000 Subject: r13260: Fix stupid bug Volker found for big-endian machines. Jeremy. --- source/include/smb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/include/smb.h b/source/include/smb.h index fba02565d8f..315eb3233a8 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -173,7 +173,7 @@ typedef smb_ucs2_t wfstring[FSTRING_LEN]; #define UCS2_CHAR(c) ((c) << UCS2_SHIFT) /* return an ascii version of a ucs2 character */ -#define UCS2_TO_CHAR(c) ((c) & 0xff) +#define UCS2_TO_CHAR(c) (((c) >> UCS2_SHIFT) & 0xff) /* Copy into a smb_ucs2_t from a possibly unaligned buffer. Return the copied smb_ucs2_t */ #define COPY_UCS2_CHAR(dest,src) (((unsigned char *)(dest))[0] = ((unsigned char *)(src))[0],\ -- cgit From 29232e34dc5a6eccb590f05918bda629e156b4b2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 31 Jan 2006 21:54:24 +0000 Subject: r13262: Arrgggg. Fix smbstatus and swat status to ignore bloody placeholder share mode entries (I hate these - I've had to add this filter code now to too many places :-). Jeremy. --- source/utils/status.c | 5 +++++ source/web/statuspage.c | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/source/utils/status.c b/source/utils/status.c index 2aed68be897..c334fe6982d 100644 --- a/source/utils/status.c +++ b/source/utils/status.c @@ -101,6 +101,11 @@ static BOOL Ucrit_addPid( pid_t pid ) static void print_share_mode(const struct share_mode_entry *e, const char *sharepath, const char *fname) { static int count; + + if (!is_valid_share_mode_entry(e)) { + return; + } + if (count==0) { d_printf("Locked files:\n"); d_printf("Pid DenyMode Access R/W Oplock SharePath Name\n"); diff --git a/source/web/statuspage.c b/source/web/statuspage.c index 24d7eaf72e7..7430f4ebf59 100644 --- a/source/web/statuspage.c +++ b/source/web/statuspage.c @@ -109,7 +109,13 @@ static char *tstring(time_t t) static void print_share_mode(const struct share_mode_entry *e, const char *sharepath, const char *fname) { char *utf8_fname; - int deny_mode = map_share_mode_to_deny_mode(e->share_access, + int deny_mode; + + if (!is_valid_share_mode_entry(e)) { + return; + } + + deny_mode = map_share_mode_to_deny_mode(e->share_access, e->private_options); printf("%s",_(mapPid2Machine(e->pid))); -- cgit From 325d2f7a76c7b3472b33b3aa13c45ebf04d7d736 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 1 Feb 2006 04:14:07 +0000 Subject: r13274: Fix for bug #3467. Not a show stopper. jason qian was a *fantastic* help in tracking this down. Jeremy. --- source/include/smb.h | 1 + source/libsmb/smb_share_modes.c | 2 ++ source/locking/locking.c | 20 +++++++++++++++--- source/smbd/close.c | 4 ++-- source/smbd/open.c | 46 ++++++++++++++++++++--------------------- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index 315eb3233a8..ac268ea763f 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -657,6 +657,7 @@ struct share_mode_lock { int num_share_modes; struct share_mode_entry *share_modes; BOOL delete_on_close; + BOOL initial_delete_on_close; BOOL fresh; BOOL modified; }; diff --git a/source/libsmb/smb_share_modes.c b/source/libsmb/smb_share_modes.c index 43f25cd3787..86071ee2e91 100644 --- a/source/libsmb/smb_share_modes.c +++ b/source/libsmb/smb_share_modes.c @@ -123,6 +123,7 @@ struct locking_data { struct { int num_share_mode_entries; BOOL delete_on_close; + BOOL initial_delete_on_close; } s; struct share_mode_entry dummy; /* Needed for alignment. */ } u; @@ -282,6 +283,7 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, ld = (struct locking_data *)db_data.dptr; ld->u.s.num_share_mode_entries = 1; ld->u.s.delete_on_close = 0; + ld->u.s.initial_delete_on_close = 0; shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry)); create_share_mode_entry(shares, new_entry); diff --git a/source/locking/locking.c b/source/locking/locking.c index e31ead30e4e..e8309582fd9 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -49,6 +49,7 @@ struct locking_data { struct { int num_share_mode_entries; BOOL delete_on_close; + BOOL initial_delete_on_close; /* Only set at NTCreateX if file was created. */ } s; struct share_mode_entry dummy; /* Needed for alignment. */ } u; @@ -435,11 +436,15 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) data = (struct locking_data *)dbuf.dptr; lck->delete_on_close = data->u.s.delete_on_close; + lck->initial_delete_on_close = data->u.s.initial_delete_on_close; lck->num_share_modes = data->u.s.num_share_mode_entries; DEBUG(10, ("parse_share_modes: delete_on_close: %d, " - "num_share_modes: %d\n", lck->delete_on_close, - lck->num_share_modes)); + "initial_delete_on_close: %d, " + "num_share_modes: %d\n", + lck->delete_on_close, + lck->initial_delete_on_close, + lck->num_share_modes)); if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { DEBUG(0, ("invalid number of share modes: %d\n", @@ -535,8 +540,10 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) ZERO_STRUCTP(data); data->u.s.num_share_mode_entries = lck->num_share_modes; data->u.s.delete_on_close = lck->delete_on_close; - DEBUG(10, ("unparse_share_modes: del: %d, num: %d\n", + data->u.s.initial_delete_on_close = lck->initial_delete_on_close; + DEBUG(10, ("unparse_share_modes: del: %d, initial del %d, num: %d\n", data->u.s.delete_on_close, + data->u.s.initial_delete_on_close, data->u.s.num_share_mode_entries)); memcpy(result.dptr + sizeof(*data), lck->share_modes, sizeof(struct share_mode_entry)*lck->num_share_modes); @@ -613,6 +620,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, lck->num_share_modes = 0; lck->share_modes = NULL; lck->delete_on_close = False; + lck->initial_delete_on_close = False; lck->fresh = False; lck->modified = False; @@ -1046,6 +1054,7 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, changed the delete on close flag. This will be noticed in the close code, the last closer will delete the file if flag is set. + Note that setting this to any value clears the initial_delete_on_close flag. ****************************************************************************/ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close) @@ -1070,6 +1079,11 @@ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close) lck->modified = True; } + if (lck->initial_delete_on_close) { + lck->initial_delete_on_close = False; + lck->modified = True; + } + talloc_free(lck); return True; } diff --git a/source/smbd/close.c b/source/smbd/close.c index c0d87b1b212..d284c82f442 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -209,7 +209,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) DEBUG(0, ("close_file: Could not delete share entry for file %s\n", fsp->fsp_name)); } - delete_file = lck->delete_on_close; + delete_file = (lck->delete_on_close | lck->initial_delete_on_close); if (delete_file) { int i; @@ -345,7 +345,7 @@ static int close_directory(files_struct *fsp, BOOL normal_close) DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name)); } - delete_dir = lck->delete_on_close; + delete_dir = (lck->delete_on_close | lck->initial_delete_on_close); talloc_free(lck); diff --git a/source/smbd/open.c b/source/smbd/open.c index 0ccac592d61..dd2731c8973 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1660,32 +1660,28 @@ files_struct *open_file_ntcreate(connection_struct *conn, } set_share_mode(lck, fsp, 0, fsp->oplock_type); - if (create_options & FILE_DELETE_ON_CLOSE) { - uint32 dosattr= existing_dos_attributes; - NTSTATUS result; - - if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) { - dosattr = new_dos_attributes; - } - - result = can_set_delete_on_close(fsp, True, dosattr); - if (!NT_STATUS_IS_OK(result)) { - /* Remember to delete the mode we just added. */ - del_share_mode(lck, fsp); - talloc_free(lck); - fd_close(conn,fsp); - file_free(fsp); - set_saved_ntstatus(result); - return NULL; + /* Handle strange delete on close create semantics. */ + if (create_options & FILE_DELETE_ON_CLOSE) { + NTSTATUS result = can_set_delete_on_close(fsp, True, new_dos_attributes); + + if (!NT_STATUS_IS_OK(result)) { + /* Remember to delete the mode we just added. */ + del_share_mode(lck, fsp); + talloc_free(lck); + fd_close(conn,fsp); + file_free(fsp); + set_saved_ntstatus(result); + return NULL; + } + /* Note that here we set the *inital* delete on close flag, + not the regular one. */ + lck->initial_delete_on_close = True; + lck->modified = True; } - lck->delete_on_close = True; - lck->modified = True; - } - if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || - info == FILE_WAS_SUPERSEDED) { /* Files should be initially set as archive */ if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { @@ -1976,7 +1972,9 @@ files_struct *open_directory(connection_struct *conn, set_share_mode(lck, fsp, 0, NO_OPLOCK); - if (create_options & FILE_DELETE_ON_CLOSE) { + if ((create_options & FILE_DELETE_ON_CLOSE) && + (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + info == FILE_WAS_SUPERSEDED)) { status = can_set_delete_on_close(fsp, True, 0); if (!NT_STATUS_IS_OK(status)) { set_saved_ntstatus(status); @@ -1985,7 +1983,7 @@ files_struct *open_directory(connection_struct *conn, return NULL; } - lck->delete_on_close = True; + lck->initial_delete_on_close = True; lck->modified = True; } -- cgit From 1d5c86f945f9235103dbb5226760dfba2935e0c9 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 1 Feb 2006 20:29:41 +0000 Subject: r13286: changing target file in another branch --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index d6c5e15bdf7..55f9773d1b8 100644 --- a/README +++ b/README @@ -223,3 +223,5 @@ As well as general information and documentation, this also has searchable archives of the mailing list and a user survey that shows who else is using this package. Have you registered with the survey yet? :-) + +; end of file -- cgit From 3f98551216c3564c573b1dfdb5f4fc015451a8fb Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 1 Feb 2006 20:30:46 +0000 Subject: r13287: removning readme file --- README | 227 ----------------------------------------------------------------- 1 file changed, 227 deletions(-) delete mode 100644 README diff --git a/README b/README deleted file mode 100644 index 55f9773d1b8..00000000000 --- a/README +++ /dev/null @@ -1,227 +0,0 @@ -This is a development version of Samba, the free SMB and CIFS client and -server for UNIX and other operating systems. Samba is maintained by -the Samba Team, who support the original author, Andrew Tridgell. - ->>>> Please read THE WHOLE of this file as it gives important information ->>>> about the configuration and use of Samba. - -NOTE: Installation instructions may be found in - docs/htmldocs/Samba-HOWTO-Collection/install.html - -This software is freely distributable under the GNU public license, a -copy of which you should have received with this software (in a file -called COPYING). - - -WHAT IS SMB/CIFS? -================= - -This is a big question. - -The very short answer is that it is the protocol by which a lot of -PC-related machines share files and printers and other information -such as lists of available files and printers. Operating systems that -support this natively include Windows 9x, Windows NT (and derivatives), -OS/2, Mac OS X and Linux. Add on packages that achieve the same -thing are available for DOS, Windows 3.1, VMS, Unix of all kinds, -MVS, and more. Some Web Browsers can speak this protocol as well -(smb://). Alternatives to SMB include Netware, NFS, Appletalk, -Banyan Vines, Decnet etc; many of these have advantages but none are -both public specifications and widely implemented in desktop machines -by default. - -The Common Internet File system (CIFS) is what the new SMB initiative -is called. For details watch http://samba.org/cifs. - - -WHY DO PEOPLE WANT TO USE SMB? -============================== - -1. Many people want to integrate their Microsoft desktop clients - with their Unix servers. - -2. Others want to integrate their Microsoft (etc) servers with Unix - servers. This is a different problem to integrating desktop - clients. - -3. Others want to replace protocols like NFS, DecNet and Novell NCP, - especially when used with PCs. - - -WHAT CAN SAMBA DO? -================== - -Please refer to the WHATSNEW.txt included with this README for -a list of features in the latest Samba release. - -Here is a very short list of what samba includes, and what it does. -For many networks this can be simply summarized by "Samba provides -a complete replacement for Windows NT, Warp, NFS or Netware servers." - -- a SMB server, to provide Windows NT and LAN Manager-style file and print - services to SMB clients such as Windows 95, Warp Server, smbfs and others. - -- a Windows NT 4.0 Domain Controller replacement. - -- a file/print server that can act as a member of a Windows NT 4.0 - or Active Directory domain. - -- a NetBIOS (rfc1001/1002) nameserver, which amongst other things gives - browsing support. Samba can be the master browser on your LAN if you wish. - -- a ftp-like SMB client so you can access PC resources (disks and - printers) from UNIX, Netware, and other operating systems - -- a tar extension to the client for backing up PCs - -- limited command-line tool that supports some of the NT administrative - functionality, which can be used on Samba, NT workstation and NT server. - -For a much better overview have a look at the web site at -http://samba.org/samba, and browse the user survey. - -Related packages include: - -- smbfs, a Linux-only filesystem allowing you to mount remote SMB -filesystems from PCs on your Linux box. This is included as standard with -Linux 2.0 and later. - -- cifsvfs, a more advanced Linux-only filesystem allowing you to mount -remote SMB filesystems from PCs on your Linux box. This is included -as standard with Linux 2.5 and later. - - - -CONTRIBUTIONS -============= - -If you want to contribute to the development of the software then -please join the mailing list. The Samba team accepts patches -(preferably in "diff -u" format, see http://samba.org/samba/devel/ -for more details) and are always glad to receive feedback or -suggestions to the address samba@lists.samba.org. More information -on the various Samba mailing lists can be found at http://lists.samba.org/. - -You can also get the Samba sourcecode straight from the Subversion tree - see -http://samba.org/samba/subversion.html. - -You could also send hardware/software/money/jewelry or pre-paid pizza -vouchers directly to Andrew. The pizza vouchers would be especially -welcome, in fact there is a special field in the survey for people who -have paid up their pizza :-) - -If you like a particular feature then look through the Subversion change-log -(on the web at http://websvn.samba.org/cgi-bin/viewcvs.cgi) and see -who added it, then send them an email. - -Remember that free software of this kind lives or dies by the response -we get. If no one tells us they like it then we'll probably move onto -something else. However, as you can see from the user survey quite a lot of -people do seem to like it at the moment :-) - - -MORE INFO -========= - -DOCUMENTATION -------------- - -There is quite a bit of documentation included with the package, -including man pages, and lots of .html files with hints and useful -info. This is also available from the web page. There is a growing -collection of information under docs/. - -A list of Samba documentation in languages other than English is -available on the web page. - -If you would like to help with the documentation (and we _need_ help!) -then have a look at the mailing list samba-docs, archived at -http://lists.samba.org/listinfo/samba-docs/ - - -MAILING LIST ------------- - -Please do NOT send subscription/unsubscription requests to the lists! - -There is a mailing list for discussion of Samba. For details go to - or send mail to - -There is also an announcement mailing list where new versions are -announced. To subscribe go to or send mail -to . All announcements also -go to the samba list, so you only need to be on one. - -For details of other Samba mailing lists and for access to archives, see - - - -MAILING LIST ETIQUETTE ----------------------- - -A few tips when submitting to this or any mailing list. - -1. Make your subject short and descriptive. Avoid the words "help" or - "Samba" in the subject. The readers of this list already know that - a) you need help, and b) you are writing about samba (of course, - you may need to distinguish between Samba PDC and other file - sharing software). Avoid phrases such as "what is" and "how do - i". Some good subject lines might look like "Slow response with - Excel files" or "Migrating from Samba PDC to NT PDC". - -2. If you include the original message in your reply, trim it so that - only the relevant lines, enough to establish context, are - included. Chances are (since this is a mailing list) we've already - read the original message. - -3. Trim irrelevant headers from the original message in your - reply. All we need to see is a) From, b) Date, and c) Subject. We - don't even really need the Subject, if you haven't changed - it. Better yet is to just preface the original message with "On - [date] [someone] wrote:". - -4. Please don't reply to or argue about spam, spam filters or viruses - on any Samba lists. We do have a spam filtering system that is - working quite well thank you very much but occasionally unwanted - messages slip through. Deal with it. - -5. Never say "Me too." It doesn't help anyone solve the - problem. Instead, if you ARE having the same problem, give more - information. Have you seen something that the other writer hasn't - mentioned, which may be helpful? - -6. If you ask about a problem, then come up with the solution on your - own or through another source, by all means post it. Someone else - may have the same problem and is waiting for an answer, but never - hears of it. - -7. Give as much *relevant* information as possible such as Samba - release number, OS, kernel version, etc... - -8. RTFM. Google. groups.google.com. - - -NEWS GROUP ----------- - -You might also like to look at the usenet news group comp.protocols.smb -as it often contains lots of useful info and is frequented by lots of -Samba users. The newsgroup was initially setup by people on the Samba -mailing list. It is not, however, exclusive to Samba, it is a forum for -discussing the SMB protocol (which Samba implements). The samba list -is gatewayed to this newsgroup. - - -WEB SITE --------- - -A Samba WWW site has been setup with lots of useful info. Connect to: - -http://samba.org/samba/ - -As well as general information and documentation, this also has searchable -archives of the mailing list and a user survey that shows who else is using -this package. Have you registered with the survey yet? :-) - - -; end of file -- cgit From c692c6cb5dbd17139e055479cb7eb839d0cd5072 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 1 Feb 2006 20:31:28 +0000 Subject: r13288: readding readme file --- README | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 00000000000..686d1557a7e --- /dev/null +++ b/README @@ -0,0 +1,225 @@ +This is thre release version of Samba, the free SMB and CIFS client and +server for UNIX and other operating systems. Samba is maintained by +the Samba Team, who support the original author, Andrew Tridgell. + +>>>> Please read THE WHOLE of this file as it gives important information +>>>> about the configuration and use of Samba. + +NOTE: Installation instructions may be found in + docs/htmldocs/Samba-HOWTO-Collection/install.html + +This software is freely distributable under the GNU public license, a +copy of which you should have received with this software (in a file +called COPYING). + + +WHAT IS SMB/CIFS? +================= + +This is a big question. + +The very short answer is that it is the protocol by which a lot of +PC-related machines share files and printers and other information +such as lists of available files and printers. Operating systems that +support this natively include Windows 9x, Windows NT (and derivatives), +OS/2, Mac OS X and Linux. Add on packages that achieve the same +thing are available for DOS, Windows 3.1, VMS, Unix of all kinds, +MVS, and more. Some Web Browsers can speak this protocol as well +(smb://). Alternatives to SMB include Netware, NFS, Appletalk, +Banyan Vines, Decnet etc; many of these have advantages but none are +both public specifications and widely implemented in desktop machines +by default. + +The Common Internet File system (CIFS) is what the new SMB initiative +is called. For details watch http://samba.org/cifs. + + +WHY DO PEOPLE WANT TO USE SMB? +============================== + +1. Many people want to integrate their Microsoft desktop clients + with their Unix servers. + +2. Others want to integrate their Microsoft (etc) servers with Unix + servers. This is a different problem to integrating desktop + clients. + +3. Others want to replace protocols like NFS, DecNet and Novell NCP, + especially when used with PCs. + + +WHAT CAN SAMBA DO? +================== + +Please refer to the WHATSNEW.txt included with this README for +a list of features in the latest Samba release. + +Here is a very short list of what samba includes, and what it does. +For many networks this can be simply summarized by "Samba provides +a complete replacement for Windows NT, Warp, NFS or Netware servers." + +- a SMB server, to provide Windows NT and LAN Manager-style file and print + services to SMB clients such as Windows 95, Warp Server, smbfs and others. + +- a Windows NT 4.0 Domain Controller replacement. + +- a file/print server that can act as a member of a Windows NT 4.0 + or Active Directory domain. + +- a NetBIOS (rfc1001/1002) nameserver, which amongst other things gives + browsing support. Samba can be the master browser on your LAN if you wish. + +- a ftp-like SMB client so you can access PC resources (disks and + printers) from UNIX, Netware, and other operating systems + +- a tar extension to the client for backing up PCs + +- limited command-line tool that supports some of the NT administrative + functionality, which can be used on Samba, NT workstation and NT server. + +For a much better overview have a look at the web site at +http://samba.org/samba, and browse the user survey. + +Related packages include: + +- smbfs, a Linux-only filesystem allowing you to mount remote SMB +filesystems from PCs on your Linux box. This is included as standard with +Linux 2.0 and later. + +- cifsvfs, a more advanced Linux-only filesystem allowing you to mount +remote SMB filesystems from PCs on your Linux box. This is included +as standard with Linux 2.5 and later. + + + +CONTRIBUTIONS +============= + +If you want to contribute to the development of the software then +please join the mailing list. The Samba team accepts patches +(preferably in "diff -u" format, see http://samba.org/samba/devel/ +for more details) and are always glad to receive feedback or +suggestions to the address samba@lists.samba.org. More information +on the various Samba mailing lists can be found at http://lists.samba.org/. + +You can also get the Samba sourcecode straight from the Subversion tree - see +http://samba.org/samba/subversion.html. + +You could also send hardware/software/money/jewelry or pre-paid pizza +vouchers directly to Andrew. The pizza vouchers would be especially +welcome, in fact there is a special field in the survey for people who +have paid up their pizza :-) + +If you like a particular feature then look through the Subversion change-log +(on the web at http://websvn.samba.org/cgi-bin/viewcvs.cgi) and see +who added it, then send them an email. + +Remember that free software of this kind lives or dies by the response +we get. If no one tells us they like it then we'll probably move onto +something else. However, as you can see from the user survey quite a lot of +people do seem to like it at the moment :-) + + +MORE INFO +========= + +DOCUMENTATION +------------- + +There is quite a bit of documentation included with the package, +including man pages, and lots of .html files with hints and useful +info. This is also available from the web page. There is a growing +collection of information under docs/. + +A list of Samba documentation in languages other than English is +available on the web page. + +If you would like to help with the documentation (and we _need_ help!) +then have a look at the mailing list samba-docs, archived at +http://lists.samba.org/listinfo/samba-docs/ + + +MAILING LIST +------------ + +Please do NOT send subscription/unsubscription requests to the lists! + +There is a mailing list for discussion of Samba. For details go to + or send mail to + +There is also an announcement mailing list where new versions are +announced. To subscribe go to or send mail +to . All announcements also +go to the samba list, so you only need to be on one. + +For details of other Samba mailing lists and for access to archives, see + + + +MAILING LIST ETIQUETTE +---------------------- + +A few tips when submitting to this or any mailing list. + +1. Make your subject short and descriptive. Avoid the words "help" or + "Samba" in the subject. The readers of this list already know that + a) you need help, and b) you are writing about samba (of course, + you may need to distinguish between Samba PDC and other file + sharing software). Avoid phrases such as "what is" and "how do + i". Some good subject lines might look like "Slow response with + Excel files" or "Migrating from Samba PDC to NT PDC". + +2. If you include the original message in your reply, trim it so that + only the relevant lines, enough to establish context, are + included. Chances are (since this is a mailing list) we've already + read the original message. + +3. Trim irrelevant headers from the original message in your + reply. All we need to see is a) From, b) Date, and c) Subject. We + don't even really need the Subject, if you haven't changed + it. Better yet is to just preface the original message with "On + [date] [someone] wrote:". + +4. Please don't reply to or argue about spam, spam filters or viruses + on any Samba lists. We do have a spam filtering system that is + working quite well thank you very much but occasionally unwanted + messages slip through. Deal with it. + +5. Never say "Me too." It doesn't help anyone solve the + problem. Instead, if you ARE having the same problem, give more + information. Have you seen something that the other writer hasn't + mentioned, which may be helpful? + +6. If you ask about a problem, then come up with the solution on your + own or through another source, by all means post it. Someone else + may have the same problem and is waiting for an answer, but never + hears of it. + +7. Give as much *relevant* information as possible such as Samba + release number, OS, kernel version, etc... + +8. RTFM. Google. groups.google.com. + + +NEWS GROUP +---------- + +You might also like to look at the usenet news group comp.protocols.smb +as it often contains lots of useful info and is frequented by lots of +Samba users. The newsgroup was initially setup by people on the Samba +mailing list. It is not, however, exclusive to Samba, it is a forum for +discussing the SMB protocol (which Samba implements). The samba list +is gatewayed to this newsgroup. + + +WEB SITE +-------- + +A Samba WWW site has been setup with lots of useful info. Connect to: + +http://samba.org/samba/ + +As well as general information and documentation, this also has searchable +archives of the mailing list and a user survey that shows who else is using +this package. Have you registered with the survey yet? :-) + -- cgit From 2841639969d0f9a1080c5a03821780af111e2924 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 2 Feb 2006 16:25:58 +0000 Subject: r13290: Adding Account Policy LDAP attributes for eDirectory schema. Guenther --- examples/LDAP/samba-nds.schema | 53 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/examples/LDAP/samba-nds.schema b/examples/LDAP/samba-nds.schema index 7bfa5040f87..8e8c5bcdf3a 100644 --- a/examples/LDAP/samba-nds.schema +++ b/examples/LDAP/samba-nds.schema @@ -234,6 +234,57 @@ changetype: modify add: attributetypes attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + + ####################################################################### ## objectClasses used by Samba 3.0 schema ## ####################################################################### @@ -268,7 +319,7 @@ objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DESC 'Samba T dn: cn=schema changetype: modify add: objectClasses -objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase )) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange )) ## ## used for idmap_ldap module -- cgit From d13e343dc7bfa1e30d7b54b59ab202b3f52ea954 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Feb 2006 16:38:37 +0000 Subject: r13291: NT checks the minimum password age dynamically. That means we have to ignore the sambapwdmustchange field if we can access the corresponding account policy and calculate it dynamically based on the pwdlastset field. Volker --- source/smbd/chgpasswd.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index 5a179dbf478..bb305193196 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -1010,15 +1010,31 @@ static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext) NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) { BOOL ret; - uint32 min_len; + uint32 min_len, min_age; struct passwd *pass = NULL; const char *username = pdb_get_username(hnd); + time_t last_change_time = pdb_get_pass_last_set_time(hnd); time_t can_change_time = pdb_get_pass_can_change_time(hnd); - if ((can_change_time != 0) && (time(NULL) < can_change_time)) { - DEBUG(1, ("user %s cannot change password now, must wait until %s\n", - username, http_timestring(can_change_time))); - return NT_STATUS_ACCOUNT_RESTRICTION; + if (pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &min_age)) { + /* + * Windows calculates the minimum password age check + * dynamically, it basically ignores the pwdcanchange + * timestamp. Do likewise. + */ + if (last_change_time + min_age > time(NULL)) { + DEBUG(1, ("user %s cannot change password now, must " + "wait until %s\n", username, + http_timestring(last_change_time+min_age))); + return NT_STATUS_ACCOUNT_RESTRICTION; + } + } else { + if ((can_change_time != 0) && (time(NULL) < can_change_time)) { + DEBUG(1, ("user %s cannot change password now, must " + "wait until %s\n", username, + http_timestring(can_change_time))); + return NT_STATUS_ACCOUNT_RESTRICTION; + } } if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { -- cgit From 130b5e80f1917a3eb52568ce114af465ad068c52 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 2 Feb 2006 20:44:50 +0000 Subject: r13293: Rather a big patch I'm afraid, but this should fix bug #3347 by saving the UNIX token used to set a delete on close flag, and using it when doing the delete. libsmbsharemodes.so still needs updating to cope with this change. Samba4 torture tests to follow. Jeremy. --- source/include/smb.h | 138 +++++++++++++++----------------- source/lib/smbrun.c | 8 +- source/lib/substitute.c | 8 +- source/locking/locking.c | 157 +++++++++++++++++++++++++++++++++---- source/modules/vfs_fake_perms.c | 8 +- source/printing/nt_printing.c | 14 ++-- source/printing/printfsp.c | 4 +- source/printing/printing.c | 15 ++-- source/rpc_server/srv_dfs_nt.c | 4 +- source/rpc_server/srv_lsa_nt.c | 9 +-- source/rpc_server/srv_pipe.c | 15 ++-- source/rpc_server/srv_pipe_hnd.c | 6 +- source/rpc_server/srv_spoolss_nt.c | 12 +-- source/rpc_server/srv_srvsvc_nt.c | 18 ++--- source/smbd/close.c | 66 ++++++++++++---- source/smbd/dir.c | 4 +- source/smbd/fake_file.c | 2 +- source/smbd/files.c | 6 +- source/smbd/nttrans.c | 26 +++--- source/smbd/open.c | 2 + source/smbd/posix_acls.c | 30 +++---- source/smbd/reply.c | 26 +++--- source/smbd/sec_ctx.c | 83 ++++++++++---------- source/smbd/trans2.c | 14 ++-- source/smbd/uid.c | 30 +++---- 25 files changed, 427 insertions(+), 278 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index ac268ea763f..b8211aac45c 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -253,8 +253,7 @@ typedef struct nttime_info { #define SID_MAX_SIZE ((size_t)(8+(MAXSUBAUTHS*4))) /* SID Types */ -enum SID_NAME_USE -{ +enum SID_NAME_USE { SID_NAME_USE_NONE = 0, SID_NAME_USER = 1, /* user */ SID_NAME_DOM_GRP, /* domain group */ @@ -276,19 +275,17 @@ enum SID_NAME_USE * * @sa http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/accctrl_38yn.asp **/ -typedef struct sid_info -{ - uint8 sid_rev_num; /**< SID revision number */ - uint8 num_auths; /**< Number of sub-authorities */ - uint8 id_auth[6]; /**< Identifier Authority */ - /* - * Pointer to sub-authorities. - * - * @note The values in these uint32's are in *native* byteorder, not - * neccessarily little-endian...... JRA. - */ - uint32 sub_auths[MAXSUBAUTHS]; - +typedef struct sid_info { + uint8 sid_rev_num; /**< SID revision number */ + uint8 num_auths; /**< Number of sub-authorities */ + uint8 id_auth[6]; /**< Identifier Authority */ + /* + * Pointer to sub-authorities. + * + * @note The values in these uint32's are in *native* byteorder, not + * neccessarily little-endian...... JRA. + */ + uint32 sub_auths[MAXSUBAUTHS]; } DOM_SID; /* Some well-known SIDs */ @@ -333,10 +330,16 @@ typedef struct _nt_user_token { SE_PRIV privileges; } NT_USER_TOKEN; +typedef struct _unix_token { + uid_t uid; + gid_t gid; + int ngroups; + gid_t *groups; +} UNIX_USER_TOKEN; + /* 32 bit time (sec) since 01jan1970 - cifs6.txt, section 3.5, page 30 */ -typedef struct time_info -{ - uint32 time; +typedef struct time_info { + uint32 time; } UTIME; /* Structure used when SMBwritebmpx is active */ @@ -350,17 +353,15 @@ typedef struct { BOOL wr_discard; /* discard all further data */ } write_bmpx_struct; -typedef struct write_cache -{ - SMB_OFF_T file_size; - SMB_OFF_T offset; - size_t alloc_size; - size_t data_size; - char *data; +typedef struct write_cache { + SMB_OFF_T file_size; + SMB_OFF_T offset; + size_t alloc_size; + size_t data_size; + char *data; } write_cache; -typedef struct -{ +typedef struct { smb_ucs2_t *origname; smb_ucs2_t *filename; SMB_STRUCT_STAT *statinfo; @@ -442,27 +443,23 @@ typedef struct data_blob_ { * Used in NT change-notify code. */ -typedef struct -{ +typedef struct { time_t modify_time; time_t status_time; } dir_status_struct; -struct vuid_cache_entry -{ +struct vuid_cache_entry { uint16 vuid; BOOL read_only; BOOL admin_user; }; -struct vuid_cache -{ +struct vuid_cache { unsigned int entries; struct vuid_cache_entry array[VUID_CACHE_SIZE]; }; -typedef struct -{ +typedef struct { char *name; BOOL is_wild; } name_compare_entry; @@ -482,8 +479,7 @@ struct dfree_cached_info { struct dptr_struct; -typedef struct connection_struct -{ +typedef struct connection_struct { struct connection_struct *next, *prev; TALLOC_CTX *mem_ctx; unsigned cnum; /* an index passed over the wire */ @@ -534,14 +530,10 @@ typedef struct connection_struct struct dfree_cached_info *dfree_info; } connection_struct; -struct current_user -{ +struct current_user { connection_struct *conn; uint16 vuid; - uid_t uid; - gid_t gid; - int ngroups; - gid_t *groups; + UNIX_USER_TOKEN ut; NT_USER_TOKEN *nt_user_token; }; @@ -562,42 +554,37 @@ typedef struct { enum {LPQ_QUEUED=0,LPQ_PAUSED,LPQ_SPOOLING,LPQ_PRINTING,LPQ_ERROR,LPQ_DELETING, LPQ_OFFLINE,LPQ_PAPEROUT,LPQ_PRINTED,LPQ_DELETED,LPQ_BLOCKED,LPQ_USER_INTERVENTION}; -typedef struct _print_queue_struct -{ - int job; /* normally the UNIX jobid -- see note in - printing.c:traverse_fn_delete() */ - int size; - int page_count; - int status; - int priority; - time_t time; - fstring fs_user; - fstring fs_file; +typedef struct _print_queue_struct { + int job; /* normally the UNIX jobid -- see note in + printing.c:traverse_fn_delete() */ + int size; + int page_count; + int status; + int priority; + time_t time; + fstring fs_user; + fstring fs_file; } print_queue_struct; enum {LPSTAT_OK, LPSTAT_STOPPED, LPSTAT_ERROR}; -typedef struct -{ - fstring message; - int qcount; - int status; +typedef struct { + fstring message; + int qcount; + int status; } print_status_struct; /* used for server information: client, nameserv and ipc */ -struct server_info_struct -{ - fstring name; - uint32 type; - fstring comment; - fstring domain; /* used ONLY in ipc.c NOT namework.c */ - BOOL server_added; /* used ONLY in ipc.c NOT namework.c */ +struct server_info_struct { + fstring name; + uint32 type; + fstring comment; + fstring domain; /* used ONLY in ipc.c NOT namework.c */ + BOOL server_added; /* used ONLY in ipc.c NOT namework.c */ }; - /* used for network interfaces */ -struct interface -{ +struct interface { struct interface *next, *prev; struct in_addr ip; struct in_addr bcast; @@ -656,6 +643,7 @@ struct share_mode_lock { SMB_INO_T ino; int num_share_modes; struct share_mode_entry *share_modes; + UNIX_USER_TOKEN *delete_token; BOOL delete_on_close; BOOL initial_delete_on_close; BOOL fresh; @@ -746,8 +734,7 @@ struct enum_list { void (*fn)(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid, \ enum brl_type lock_type, \ br_off start, br_off size) -struct parm_struct -{ +struct parm_struct { const char *label; parm_type type; parm_class p_class; @@ -1374,8 +1361,7 @@ enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANM enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER,SEC_DOMAIN,SEC_ADS}; /* server roles */ -enum server_types -{ +enum server_types { ROLE_STANDALONE, ROLE_DOMAIN_MEMBER, ROLE_DOMAIN_BDC, @@ -1552,8 +1538,6 @@ struct cnotify_fns { int select_time; }; - - #include "smb_macros.h" #define MAX_NETBIOSNAME_LEN 16 @@ -1621,7 +1605,6 @@ typedef struct user_struct { } user_struct; - struct unix_error_map { int unix_error; int dos_class; @@ -1744,4 +1727,7 @@ typedef struct uuid_flat { /* map readonly options */ enum mapreadonly_options {MAP_READONLY_NO, MAP_READONLY_YES, MAP_READONLY_PERMISSIONS}; +/* Different reasons for closing a file. */ +enum file_close_type {NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE}; + #endif /* _SMB_H */ diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c index 6d6d7817f1a..4f5525039f5 100644 --- a/source/lib/smbrun.c +++ b/source/lib/smbrun.c @@ -58,8 +58,8 @@ outfd (or discard it if outfd is NULL). int smbrun(const char *cmd, int *outfd) { pid_t pid; - uid_t uid = current_user.uid; - gid_t gid = current_user.gid; + uid_t uid = current_user.ut.uid; + gid_t gid = current_user.ut.gid; /* * Lose any kernel oplock capabilities we may have. @@ -189,8 +189,8 @@ sends the provided secret to the child stdin. int smbrunsecret(const char *cmd, const char *secret) { pid_t pid; - uid_t uid = current_user.uid; - gid_t gid = current_user.gid; + uid_t uid = current_user.ut.uid; + gid_t gid = current_user.ut.gid; int ifd[2]; /* diff --git a/source/lib/substitute.c b/source/lib/substitute.c index 344f6e06fdf..30e1d97ca9b 100644 --- a/source/lib/substitute.c +++ b/source/lib/substitute.c @@ -840,11 +840,11 @@ void standard_sub_snum(int snum, char *str, size_t len) /* calling uidtoname() on every substitute would be too expensive, so we cache the result here as nearly every call is for the same uid */ - if (cached_uid != current_user.uid) { - fstrcpy(cached_user, uidtoname(current_user.uid)); - cached_uid = current_user.uid; + if (cached_uid != current_user.ut.uid) { + fstrcpy(cached_user, uidtoname(current_user.ut.uid)); + cached_uid = current_user.ut.uid; } - standard_sub_advanced(snum, cached_user, "", current_user.gid, + standard_sub_advanced(snum, cached_user, "", current_user.ut.gid, smb_user_name, str, len); } diff --git a/source/locking/locking.c b/source/locking/locking.c index e8309582fd9..e558c6d74ff 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -50,6 +50,9 @@ struct locking_data { int num_share_mode_entries; BOOL delete_on_close; BOOL initial_delete_on_close; /* Only set at NTCreateX if file was created. */ + uint32 delete_token_size; /* Only valid if either of + the two previous fields + are True. */ } s; struct share_mode_entry dummy; /* Needed for alignment. */ } u; @@ -429,8 +432,7 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) int i; if (dbuf.dsize < sizeof(struct locking_data)) { - DEBUG(0, ("parse_share_modes: buffer too short\n")); - return False; + smb_panic("PANIC: parse_share_modes: buffer too short.\n"); } data = (struct locking_data *)dbuf.dptr; @@ -449,18 +451,17 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { DEBUG(0, ("invalid number of share modes: %d\n", lck->num_share_modes)); - return False; + smb_panic("PANIC: invalid number of share modes"); } lck->share_modes = NULL; - + if (lck->num_share_modes != 0) { if (dbuf.dsize < (sizeof(struct locking_data) + (lck->num_share_modes * sizeof(struct share_mode_entry)))) { - DEBUG(0, ("parse_share_modes: buffer too short\n")); - return False; + smb_panic("PANIC: parse_share_modes: buffer too short.\n"); } lck->share_modes = talloc_memdup(lck, dbuf.dptr+sizeof(*data), @@ -468,20 +469,67 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) sizeof(struct share_mode_entry)); if (lck->share_modes == NULL) { - DEBUG(0, ("talloc failed\n")); - return False; + smb_panic("talloc failed\n"); } } + /* Get any delete token. */ + if (data->u.s.delete_token_size) { + /* Each uid/gid is stored as a 4 byte value. */ + uint32 val; + uint32 *p = (uint32 *)(dbuf.dptr + sizeof(*data) + + (lck->num_share_modes * + sizeof(struct share_mode_entry))); + + if ((data->u.s.delete_token_size < 8) || (data->u.s.delete_token_size % 4) != 0) { + DEBUG(0, ("parse_share_modes: invalid token size %d\n", + data->u.s.delete_token_size)); + smb_panic("parse_share_modes: invalid token size\n"); + } + + lck->delete_token = TALLOC_P(lck, UNIX_USER_TOKEN); + if (!lck->delete_token) { + smb_panic("talloc failed\n"); + } + + /* Copy out the uid and gid. */ + memcpy(&val, p++, 4); + lck->delete_token->uid = (uid_t)val; + memcpy(&val, p++, 4); + lck->delete_token->gid = (gid_t)val; + + /* Any supplementary groups ? */ + lck->delete_token->ngroups = (data->u.s.delete_token_size > 8) ? + ((data->u.s.delete_token_size - 8)/4) : 0; + if (lck->delete_token->ngroups) { + /* Make this a talloc child of lck->delete_token. */ + lck->delete_token->groups = TALLOC_ARRAY(lck->delete_token, gid_t, + lck->delete_token->ngroups); + if (!lck->delete_token) { + smb_panic("talloc failed\n"); + } + + for (i = 0; i < lck->delete_token->ngroups; i++) { + memcpy(&val, p++, 4); + lck->delete_token->groups[i] = (gid_t)val; + } + } + + } else { + lck->delete_token = NULL; + } + /* Save off the associated service path and filename. */ lck->servicepath = talloc_strdup(lck, dbuf.dptr + sizeof(*data) + - (lck->num_share_modes * - sizeof(struct share_mode_entry))); + (lck->num_share_modes * + sizeof(struct share_mode_entry)) + + data->u.s.delete_token_size ); lck->filename = talloc_strdup(lck, dbuf.dptr + sizeof(*data) + - (lck->num_share_modes * - sizeof(struct share_mode_entry)) + - strlen(lck->servicepath) + 1 ); + (lck->num_share_modes * + sizeof(struct share_mode_entry)) + + data->u.s.delete_token_size + + strlen(lck->servicepath) + 1 ); /* * Ensure that each entry has a real process attached. @@ -528,6 +576,7 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) result.dsize = sizeof(*data) + lck->num_share_modes * sizeof(struct share_mode_entry) + + (lck->delete_token ? (8 + (lck->delete_token->ngroups*4)) : 0) + sp_len + 1 + strlen(lck->filename) + 1; result.dptr = talloc_size(lck, result.dsize); @@ -549,6 +598,25 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) sizeof(struct share_mode_entry)*lck->num_share_modes); offset = sizeof(*data) + sizeof(struct share_mode_entry)*lck->num_share_modes; + + /* Store any delete on close token. */ + if (lck->delete_token) { + uint32 val; + uint32 *p = (uint32 *)(result.dptr + offset); + + val = (uint32)lck->delete_token->uid; + memcpy(p++, &val, 4); + + val = (uint32)lck->delete_token->uid; + memcpy(p++, &val, 4); + + for (i = 0; i < lck->delete_token->ngroups; i++) { + val = (uint32)lck->delete_token->groups[i]; + memcpy(p++, &val, 4); + } + offset = ((char *)p - result.dptr); + } + safe_strcpy(result.dptr + offset, lck->servicepath, result.dsize - offset - 1); offset += sp_len + 1; @@ -619,6 +687,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, lck->ino = ino; lck->num_share_modes = 0; lck->share_modes = NULL; + lck->delete_token = NULL; lck->delete_on_close = False; lck->initial_delete_on_close = False; lck->fresh = False; @@ -1047,6 +1116,55 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, return NT_STATUS_OK; } +/************************************************************************* + Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail. + (Should this be in locking.c.... ?). +*************************************************************************/ + +static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok) +{ + UNIX_USER_TOKEN *cpy; + + if (tok == NULL) { + return NULL; + } + + cpy = TALLOC_P(ctx, UNIX_USER_TOKEN); + if (!cpy) { + return NULL; + } + + cpy->uid = tok->uid; + cpy->gid = tok->gid; + cpy->ngroups = tok->ngroups; + if (tok->ngroups) { + /* Make this a talloc child of cpy. */ + cpy->groups = TALLOC_ARRAY(cpy, gid_t, tok->ngroups); + if (!cpy->groups) { + return NULL; + } + memcpy(cpy->groups, tok->groups, tok->ngroups * sizeof(gid_t)); + } + return cpy; +} + +/**************************************************************************** + Replace the delete on close token. +****************************************************************************/ + +void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok) +{ + /* Ensure there's no token. */ + if (lck->delete_token) { + talloc_free(lck->delete_token); /* Also deletes groups... */ + lck->delete_token = NULL; + } + + /* Copy the new token (can be NULL). */ + lck->delete_token = copy_unix_token(lck, tok); + lck->modified = True; +} + /**************************************************************************** Sets the delete on close flag over all share modes on this file. Modify the share mode entry for all files open @@ -1055,9 +1173,11 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, in the close code, the last closer will delete the file if flag is set. Note that setting this to any value clears the initial_delete_on_close flag. + If delete_on_close is True this makes a copy of any UNIX_USER_TOKEN into the + lck entry. ****************************************************************************/ -BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close) +BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close, UNIX_USER_TOKEN *tok) { struct share_mode_lock *lck; @@ -1074,8 +1194,13 @@ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close) if (lck == NULL) { return False; } + if (lck->delete_on_close != delete_on_close) { + set_delete_on_close_token(lck, tok); lck->delete_on_close = delete_on_close; + if (delete_on_close) { + SMB_ASSERT(lck->delete_token != NULL); + } lck->modified = True; } @@ -1105,9 +1230,11 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, data = (struct locking_data *)dbuf.dptr; shares = (struct share_mode_entry *)(dbuf.dptr + sizeof(*data)); sharepath = dbuf.dptr + sizeof(*data) + - data->u.s.num_share_mode_entries*sizeof(*shares); + data->u.s.num_share_mode_entries*sizeof(*shares) + + data->u.s.delete_token_size; fname = dbuf.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares) + + data->u.s.delete_token_size + strlen(sharepath) + 1; for (i=0;iu.s.num_share_mode_entries;i++) { diff --git a/source/modules/vfs_fake_perms.c b/source/modules/vfs_fake_perms.c index 4d10ea5f337..decbe01d3ca 100644 --- a/source/modules/vfs_fake_perms.c +++ b/source/modules/vfs_fake_perms.c @@ -40,8 +40,8 @@ static int fake_perms_stat(vfs_handle_struct *handle, connection_struct *conn, c } else { sbuf->st_mode = S_IRWXU; } - sbuf->st_uid = current_user.uid; - sbuf->st_gid = current_user.gid; + sbuf->st_uid = current_user.ut.uid; + sbuf->st_gid = current_user.ut.gid; } return ret; @@ -58,8 +58,8 @@ static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd } else { sbuf->st_mode = S_IRWXU; } - sbuf->st_uid = current_user.uid; - sbuf->st_gid = current_user.gid; + sbuf->st_uid = current_user.ut.uid; + sbuf->st_gid = current_user.ut.gid; } return ret; } diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 3649da1ac05..a91c2a5c70b 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -1296,7 +1296,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time)); } } - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); /* Get file version info (if available) for new file */ pstrcpy(filepath, new_file); @@ -1332,7 +1332,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time)); } } - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); if (use_version && (new_major != old_major || new_minor != old_minor)) { /* Compare versions and choose the larger version number */ @@ -1361,7 +1361,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr error_exit: if(fsp) - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); return -1; } @@ -1486,7 +1486,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n", driverpath, cversion)); - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); close_cnum(conn, user->vuid); unbecome_user(); *perr = WERR_OK; @@ -1496,7 +1496,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ error_exit: if(fsp) - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); close_cnum(conn, user->vuid); unbecome_user(); @@ -5275,7 +5275,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* Always allow root or SE_PRINT_OPERATROR to do anything */ - if ( user->uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) { + if ( user->ut.uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) { return True; } @@ -5327,7 +5327,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* see if we need to try the printer admin list */ if ( access_granted == 0 ) { - if ( user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups) ) + if ( user_in_list(uidtoname(user->ut.uid), lp_printer_admin(snum), user->ut.groups, user->ut.ngroups) ) return True; } diff --git a/source/printing/printfsp.c b/source/printing/printfsp.c index eb81dc4536f..c248851822b 100644 --- a/source/printing/printfsp.c +++ b/source/printing/printfsp.c @@ -94,7 +94,7 @@ files_struct *print_fsp_open(connection_struct *conn, const char *fname) Print a file - called on closing the file. ****************************************************************************/ -void print_fsp_end(files_struct *fsp, BOOL normal_close) +void print_fsp_end(files_struct *fsp, enum file_close_type close_type) { uint32 jobid; fstring sharename; @@ -117,5 +117,5 @@ void print_fsp_end(files_struct *fsp, BOOL normal_close) return; } - print_job_end(SNUM(fsp->conn),jobid, normal_close); + print_job_end(SNUM(fsp->conn),jobid, close_type); } diff --git a/source/printing/printing.c b/source/printing/printing.c index 6e74095f719..82b9a7f74e3 100644 --- a/source/printing/printing.c +++ b/source/printing/printing.c @@ -1932,7 +1932,7 @@ static BOOL is_owner(struct current_user *user, int snum, uint32 jobid) if ((vuser = get_valid_user_struct(user->vuid)) != NULL) { return strequal(pjob->user, vuser->user.smb_name); } else { - return strequal(pjob->user, uidtoname(user->uid)); + return strequal(pjob->user, uidtoname(user->ut.uid)); } } @@ -1963,7 +1963,7 @@ BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR sys_adminlog( LOG_ERR, "Permission denied-- user not allowed to delete, \ pause, or resume print job. User name: %s. Printer name: %s.", - uidtoname(user->uid), PRINTERNAME(snum) ); + uidtoname(user->ut.uid), PRINTERNAME(snum) ); /* END_ADMIN_LOG */ return False; @@ -2030,7 +2030,7 @@ BOOL print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR * sys_adminlog( LOG_ERR, "Permission denied-- user not allowed to delete, \ pause, or resume print job. User name: %s. Printer name: %s.", - uidtoname(user->uid), PRINTERNAME(snum) ); + uidtoname(user->ut.uid), PRINTERNAME(snum) ); /* END_ADMIN_LOG */ *errcode = WERR_ACCESS_DENIED; @@ -2085,7 +2085,7 @@ BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR sys_adminlog( LOG_ERR, "Permission denied-- user not allowed to delete, \ pause, or resume print job. User name: %s. Printer name: %s.", - uidtoname(user->uid), PRINTERNAME(snum) ); + uidtoname(user->ut.uid), PRINTERNAME(snum) ); /* END_ADMIN_LOG */ return False; } @@ -2366,7 +2366,7 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE if ((vuser = get_valid_user_struct(user->vuid)) != NULL) { fstrcpy(pjob.user, vuser->user.smb_name); } else { - fstrcpy(pjob.user, uidtoname(user->uid)); + fstrcpy(pjob.user, uidtoname(user->ut.uid)); } fstrcpy(pjob.queuename, lp_const_servicename(snum)); @@ -2437,7 +2437,7 @@ void print_job_endpage(int snum, uint32 jobid) error. ****************************************************************************/ -BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) +BOOL print_job_end(int snum, uint32 jobid, enum file_close_type close_type) { const char* sharename = lp_const_servicename(snum); struct printjob *pjob; @@ -2453,7 +2453,8 @@ BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) if (pjob->spooled || pjob->pid != sys_getpid()) return False; - if (normal_close && (sys_fstat(pjob->fd, &sbuf) == 0)) { + if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && + (sys_fstat(pjob->fd, &sbuf) == 0)) { pjob->size = sbuf.st_size; close(pjob->fd); pjob->fd = -1; diff --git a/source/rpc_server/srv_dfs_nt.c b/source/rpc_server/srv_dfs_nt.c index f61348ee05d..63e4d4e9b7c 100644 --- a/source/rpc_server/srv_dfs_nt.c +++ b/source/rpc_server/srv_dfs_nt.c @@ -52,7 +52,7 @@ WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u) get_current_user(&user,p); - if (user.uid != 0) { + if (user.ut.uid != 0) { DEBUG(10,("_dfs_add: uid != 0. Access denied.\n")); return WERR_ACCESS_DENIED; } @@ -115,7 +115,7 @@ WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, get_current_user(&user,p); - if (user.uid != 0) { + if (user.ut.uid != 0) { DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n")); return WERR_ACCESS_DENIED; } diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c index 6cd673550ec..f48f3e863a8 100644 --- a/source/rpc_server/srv_lsa_nt.c +++ b/source/rpc_server/srv_lsa_nt.c @@ -1198,7 +1198,7 @@ NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u account_pol.tdb was already opened as root, this is all we have */ get_current_user( &user, p ); - if ( user.uid != sec_initial_uid() + if ( user.ut.uid != sec_initial_uid() && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) { return NT_STATUS_ACCESS_DENIED; @@ -1239,7 +1239,7 @@ NTSTATUS _lsa_removeprivs(pipes_struct *p, LSA_Q_REMOVEPRIVS *q_u, LSA_R_REMOVEP account_pol.tdb was already opened as root, this is all we have */ get_current_user( &user, p ); - if ( user.uid != sec_initial_uid() + if ( user.ut.uid != sec_initial_uid() && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) { return NT_STATUS_ACCESS_DENIED; @@ -1401,7 +1401,7 @@ NTSTATUS _lsa_add_acct_rights(pipes_struct *p, LSA_Q_ADD_ACCT_RIGHTS *q_u, LSA_R account_pol.tdb was already opened as root, this is all we have */ get_current_user( &user, p ); - if ( user.uid != sec_initial_uid() + if ( user.ut.uid != sec_initial_uid() && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) { return NT_STATUS_ACCESS_DENIED; @@ -1459,7 +1459,7 @@ NTSTATUS _lsa_remove_acct_rights(pipes_struct *p, LSA_Q_REMOVE_ACCT_RIGHTS *q_u, account_pol.tdb was already opened as root, this is all we have */ get_current_user( &user, p ); - if ( user.uid != sec_initial_uid() + if ( user.ut.uid != sec_initial_uid() && !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) { return NT_STATUS_ACCESS_DENIED; @@ -1573,4 +1573,3 @@ NTSTATUS _lsa_lookup_priv_value(pipes_struct *p, LSA_Q_LOOKUP_PRIV_VALUE *q_u, L return NT_STATUS_OK; } - diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c index ecf79d0c1f3..381adbe6358 100644 --- a/source/rpc_server/srv_pipe.c +++ b/source/rpc_server/srv_pipe.c @@ -617,8 +617,8 @@ static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) /* Set up for non-authenticated user. */ delete_nt_token(&p->pipe_user.nt_user_token); - p->pipe_user.ngroups = 0; - SAFE_FREE( p->pipe_user.groups); + p->pipe_user.ut.ngroups = 0; + SAFE_FREE( p->pipe_user.ut.groups); status = auth_ntlmssp_update(a, *p_resp_blob, &reply); @@ -641,8 +641,8 @@ static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) * Store the UNIX credential data (uid/gid pair) in the pipe structure. */ - p->pipe_user.uid = a->server_info->uid; - p->pipe_user.gid = a->server_info->gid; + p->pipe_user.ut.uid = a->server_info->uid; + p->pipe_user.ut.gid = a->server_info->gid; /* * Copy the session key from the ntlmssp state. @@ -654,9 +654,10 @@ static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) return False; } - p->pipe_user.ngroups = a->server_info->n_groups; - if (p->pipe_user.ngroups) { - if (!(p->pipe_user.groups = memdup(a->server_info->groups, sizeof(gid_t) * p->pipe_user.ngroups))) { + p->pipe_user.ut.ngroups = a->server_info->n_groups; + if (p->pipe_user.ut.ngroups) { + if (!(p->pipe_user.ut.groups = memdup(a->server_info->groups, + sizeof(gid_t) * p->pipe_user.ut.ngroups))) { DEBUG(0,("failed to memdup group list to p->pipe_user.groups\n")); return False; } diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c index 5fb84115cc3..37d3ef64c0b 100644 --- a/source/rpc_server/srv_pipe_hnd.c +++ b/source/rpc_server/srv_pipe_hnd.c @@ -343,8 +343,8 @@ static void *make_internal_rpc_pipe_p(char *pipe_name, ZERO_STRUCT(p->pipe_user); - p->pipe_user.uid = (uid_t)-1; - p->pipe_user.gid = (gid_t)-1; + p->pipe_user.ut.uid = (uid_t)-1; + p->pipe_user.ut.gid = (gid_t)-1; /* Store the session key and NT_TOKEN */ if (vuser) { @@ -1224,7 +1224,7 @@ static BOOL close_internal_rpc_pipe_hnd(void *np_conn) delete_nt_token(&p->pipe_user.nt_user_token); data_blob_free(&p->session_key); - SAFE_FREE(p->pipe_user.groups); + SAFE_FREE(p->pipe_user.ut.groups); DLIST_REMOVE(InternalPipes, p); diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index 334158bbbd2..a22d6db266c 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -1620,9 +1620,9 @@ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, and not a printer admin, then fail */ - if ( user.uid != 0 + if ( user.ut.uid != 0 && !user_has_privileges( user.nt_user_token, &se_printop ) - && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum), user.groups, user.ngroups) ) + && !user_in_list(uidtoname(user.ut.uid), lp_printer_admin(snum), user.ut.groups, user.ut.ngroups) ) { close_printer_handle(p, handle); return WERR_ACCESS_DENIED; @@ -1676,7 +1676,7 @@ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, return WERR_ACCESS_DENIED; } - if (!user_ok(uidtoname(user.uid), snum, user.groups, user.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) { + if (!user_ok(uidtoname(user.ut.uid), snum, user.ut.groups, user.ut.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) { DEBUG(3, ("access DENIED for printer open\n")); close_printer_handle(p, handle); return WERR_ACCESS_DENIED; @@ -1869,7 +1869,7 @@ static WERROR _spoolss_enddocprinter_internal(pipes_struct *p, POLICY_HND *handl return WERR_BADFID; Printer->document_started=False; - print_job_end(snum, Printer->jobid,True); + print_job_end(snum, Printer->jobid,NORMAL_CLOSE); /* error codes unhandled so far ... */ return WERR_OK; @@ -7554,12 +7554,12 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, case 3: fstrcpy(driver_name, driver.info_3->name ? driver.info_3->name : ""); sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.", - driver_name, get_drv_ver_to_os(driver.info_3->cversion),uidtoname(user.uid)); + driver_name, get_drv_ver_to_os(driver.info_3->cversion),uidtoname(user.ut.uid)); break; case 6: fstrcpy(driver_name, driver.info_6->name ? driver.info_6->name : ""); sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.", - driver_name, get_drv_ver_to_os(driver.info_6->version),uidtoname(user.uid)); + driver_name, get_drv_ver_to_os(driver.info_6->version),uidtoname(user.ut.uid)); break; } /* END_ADMIN_LOG */ diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index 65e0504e678..8150a8bf698 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -1401,7 +1401,7 @@ WERROR _srv_net_sess_del(pipes_struct *p, SRV_Q_NET_SESS_DEL *q_u, SRV_R_NET_SES /* fail out now if you are not root or not a domain admin */ - if ((user.uid != sec_initial_uid()) && + if ((user.ut.uid != sec_initial_uid()) && ( ! nt_token_check_domain_rid(p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS))) { goto done; @@ -1412,7 +1412,7 @@ WERROR _srv_net_sess_del(pipes_struct *p, SRV_Q_NET_SESS_DEL *q_u, SRV_R_NET_SES if ((strequal(session_list[snum].username, username) || username[0] == '\0' ) && strequal(session_list[snum].remote_machine, machine)) { - if (user.uid != sec_initial_uid()) { + if (user.ut.uid != sec_initial_uid()) { not_root = True; become_root(); } @@ -1572,7 +1572,7 @@ WERROR _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, S /* fail out now if you are not root and not a disk op */ - if ( user.uid != sec_initial_uid() && !is_disk_op ) + if ( user.ut.uid != sec_initial_uid() && !is_disk_op ) return WERR_ACCESS_DENIED; switch (q_u->info_level) { @@ -1739,7 +1739,7 @@ WERROR _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_S is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop ); - if (user.uid != sec_initial_uid() && !is_disk_op ) + if (user.ut.uid != sec_initial_uid() && !is_disk_op ) return WERR_ACCESS_DENIED; if (!lp_add_share_cmd() || !*lp_add_share_cmd()) { @@ -1906,7 +1906,7 @@ WERROR _srv_net_share_del(pipes_struct *p, SRV_Q_NET_SHARE_DEL *q_u, SRV_R_NET_S is_disk_op = user_has_privileges( p->pipe_user.nt_user_token, &se_diskop ); - if (user.uid != sec_initial_uid() && !is_disk_op ) + if (user.ut.uid != sec_initial_uid() && !is_disk_op ) return WERR_ACCESS_DENIED; if (!lp_delete_share_cmd() || !*lp_delete_share_cmd()) { @@ -2098,7 +2098,7 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC psd->dacl->revision = (uint16) NT4_ACL_REVISION; - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); unbecome_user(); close_cnum(conn, user.vuid); return r_u->status; @@ -2106,7 +2106,7 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC error_exit: if(fsp) { - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); } if (became_user) @@ -2207,7 +2207,7 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_ goto error_exit; } - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); unbecome_user(); close_cnum(conn, user.vuid); return r_u->status; @@ -2215,7 +2215,7 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_ error_exit: if(fsp) { - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); } if (became_user) { diff --git a/source/smbd/close.c b/source/smbd/close.c index d284c82f442..059b88ecc89 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -145,13 +145,12 @@ static void notify_deferred_opens(struct share_mode_lock *lck) /**************************************************************************** Close a file. - If normal_close is 1 then this came from a normal SMBclose (or equivalent) - operation otherwise it came as the result of some other operation such as - the closing of the connection. In the latter case printing and - magic scripts are not run. + close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE. + printing and magic scripts are only run on normal close. + delete on close is done on normal and shutdown close. ****************************************************************************/ -static int close_normal_file(files_struct *fsp, BOOL normal_close) +static int close_normal_file(files_struct *fsp, enum file_close_type close_type) { BOOL delete_file = False; connection_struct *conn = fsp->conn; @@ -187,7 +186,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) } if (fsp->print_file) { - print_fsp_end(fsp, normal_close); + print_fsp_end(fsp, close_type); file_free(fsp); return 0; } @@ -232,12 +231,26 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) * reference to a file. */ - if (normal_close && delete_file) { + if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && + delete_file && + lck->delete_token) { SMB_STRUCT_STAT sbuf; DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", fsp->fsp_name)); + /* Become the user who requested the delete. */ + + if (!push_sec_ctx()) { + smb_panic("close_file: file %s. failed to push sec_ctx.\n"); + } + + set_sec_ctx(lck->delete_token->uid, + lck->delete_token->gid, + lck->delete_token->ngroups, + lck->delete_token->groups, + NULL); + /* We can only delete the file if the name we have is still valid and hasn't been renamed. */ @@ -268,8 +281,11 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) "and unlink failed with error %s\n", fsp->fsp_name, strerror(errno) )); } - process_pending_change_notify_queue((time_t)0); } + /* unbecome user. */ + pop_sec_ctx(); + + process_pending_change_notify_queue((time_t)0); } talloc_free(lck); @@ -288,7 +304,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) } /* check for magic scripts */ - if (normal_close) { + if (close_type == NORMAL_CLOSE) { check_magic(fsp,conn); } @@ -324,7 +340,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) Close a directory opened by an NT SMB call. ****************************************************************************/ -static int close_directory(files_struct *fsp, BOOL normal_close) +static int close_directory(files_struct *fsp, enum file_close_type close_type) { struct share_mode_lock *lck = 0; BOOL delete_dir = False; @@ -349,11 +365,31 @@ static int close_directory(files_struct *fsp, BOOL normal_close) talloc_free(lck); - if (normal_close && delete_dir) { - BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name); + if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && + delete_dir && + lck->delete_token) { + BOOL ok; + + /* Become the user who requested the delete. */ + + if (!push_sec_ctx()) { + smb_panic("close_directory: failed to push sec_ctx.\n"); + } + + set_sec_ctx(lck->delete_token->uid, + lck->delete_token->gid, + lck->delete_token->ngroups, + lck->delete_token->groups, + NULL); + + ok = rmdir_internals(fsp->conn, fsp->fsp_name); + DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n", fsp->fsp_name, ok ? "succeeded" : "failed" )); + /* unbecome user. */ + pop_sec_ctx(); + /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. @@ -404,12 +440,12 @@ static int close_stat(files_struct *fsp) Close a files_struct. ****************************************************************************/ -int close_file(files_struct *fsp, BOOL normal_close) +int close_file(files_struct *fsp, enum file_close_type close_type) { if(fsp->is_directory) - return close_directory(fsp, normal_close); + return close_directory(fsp, close_type); else if (fsp->is_stat) return close_stat(fsp); else - return close_normal_file(fsp, normal_close); + return close_normal_file(fsp, close_type); } diff --git a/source/smbd/dir.c b/source/smbd/dir.c index 0635db22dbd..81fe7c40218 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -866,7 +866,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); /* No access if SD get failed. */ if (!sd_size) { @@ -929,7 +929,7 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); - close_file(fsp, False); + close_file(fsp, NORMAL_CLOSE); /* No access if SD get failed. */ if (!sd_size) diff --git a/source/smbd/fake_file.c b/source/smbd/fake_file.c index 799725a7820..1356baf1a81 100644 --- a/source/smbd/fake_file.c +++ b/source/smbd/fake_file.c @@ -109,7 +109,7 @@ files_struct *open_fake_file(connection_struct *conn, files_struct *fsp = NULL; /* access check */ - if (current_user.uid != 0) { + if (current_user.ut.uid != 0) { DEBUG(1,("open_fake_file_shared: access_denied to service[%s] file[%s] user[%s]\n", lp_servicename(SNUM(conn)),fname,conn->user)); errno = EACCES; diff --git a/source/smbd/files.c b/source/smbd/files.c index 181e17b11fb..5a545c236e6 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -148,7 +148,7 @@ void file_close_conn(connection_struct *conn) for (fsp=Files;fsp;fsp=next) { next = fsp->next; if (fsp->conn == conn) { - close_file(fsp,False); + close_file(fsp,SHUTDOWN_CLOSE); } } } @@ -164,7 +164,7 @@ void file_close_pid(uint16 smbpid) for (fsp=Files;fsp;fsp=next) { next = fsp->next; if (fsp->file_pid == smbpid) { - close_file(fsp,False); + close_file(fsp,SHUTDOWN_CLOSE); } } } @@ -222,7 +222,7 @@ void file_close_user(int vuid) for (fsp=Files;fsp;fsp=next) { next=fsp->next; if (fsp->vuid == vuid) { - close_file(fsp,False); + close_file(fsp,SHUTDOWN_CLOSE); } } } diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 72288e2c244..e12a24968b0 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -798,7 +798,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", fattr = FILE_ATTRIBUTE_NORMAL; } if (!fsp->is_directory && (fattr & aDIR)) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBntcreateX); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -812,13 +812,13 @@ create_options = 0x%x root_dir_fid = 0x%x\n", if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) { fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); if (fsp->is_directory) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBntcreateX); /* Can't set allocation size on a directory. */ return ERROR_NT(NT_STATUS_ACCESS_DENIED); } if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_DISK_FULL); } @@ -1416,7 +1416,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION); if (!NT_STATUS_IS_OK(status)) { talloc_destroy(ctx); - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); restore_case_semantics(conn, file_attributes); return ERROR_NT(status); } @@ -1427,7 +1427,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o status = set_ea(conn, fsp, fname, ea_list); talloc_destroy(ctx); if (!NT_STATUS_IS_OK(status)) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); restore_case_semantics(conn, file_attributes); return ERROR_NT(status); } @@ -1441,7 +1441,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o fattr = FILE_ATTRIBUTE_NORMAL; } if (!fsp->is_directory && (fattr & aDIR)) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1454,12 +1454,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if (allocation_size && (allocation_size > file_len)) { fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); if (fsp->is_directory) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); /* Can't set allocation size on a directory. */ return ERROR_NT(NT_STATUS_ACCESS_DENIED); } if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); return ERROR_NT(NT_STATUS_DISK_FULL); } } else { @@ -1688,7 +1688,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new status = NT_STATUS_ACCESS_DENIED; } set_saved_ntstatus(NT_STATUS_OK); - close_file(fsp1,False); + close_file(fsp1,ERROR_CLOSE); return status; } @@ -1702,12 +1702,12 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new * Thus we don't look at the error return from the * close of fsp1. */ - close_file(fsp1,False); + close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ fsp_set_pending_modtime(fsp2, sbuf1.st_mtime); - close_ret = close_file(fsp2,False); + close_ret = close_file(fsp2,NORMAL_CLOSE); /* Grrr. We have to do this as open_file_shared1 adds aARCH when it creates the file. This isn't the correct thing to do in the copy case. JRA */ @@ -2379,7 +2379,7 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, ZERO_STRUCT(qt); /* access check */ - if (current_user.uid != 0) { + if (current_user.ut.uid != 0) { DEBUG(1,("get_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)),conn->user)); return ERROR_DOS(ERRDOS,ERRnoaccess); @@ -2626,7 +2626,7 @@ static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf, ZERO_STRUCT(qt); /* access check */ - if (current_user.uid != 0) { + if (current_user.ut.uid != 0) { DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)),conn->user)); return ERROR_DOS(ERRDOS,ERRnoaccess); diff --git a/source/smbd/open.c b/source/smbd/open.c index dd2731c8973..15e814aae3c 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1678,6 +1678,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, } /* Note that here we set the *inital* delete on close flag, not the regular one. */ + set_delete_on_close_token(lck, ¤t_user.ut); lck->initial_delete_on_close = True; lck->modified = True; } @@ -1983,6 +1984,7 @@ files_struct *open_directory(connection_struct *conn, return NULL; } + set_delete_on_close_token(lck, ¤t_user.ut); lck->initial_delete_on_close = True; lck->modified = True; } diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 34497f02809..5db245ac0ce 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -929,7 +929,7 @@ static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid if (lp_force_unknown_acl_user(snum)) { /* this allows take ownership to work * reasonably */ - *puser = current_user.uid; + *puser = current_user.ut.uid; } else { DEBUG(3,("unpack_nt_owners: unable to validate" " owner sid for %s\n", @@ -950,7 +950,7 @@ static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid if (lp_force_unknown_acl_user(snum)) { /* this allows take group ownership to work * reasonably */ - *pgrp = current_user.gid; + *pgrp = current_user.ut.gid; } else { DEBUG(3,("unpack_nt_owners: unable to validate" " group sid.\n")); @@ -1024,7 +1024,7 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) /* Assume that the current user is in the current group (force group) */ - if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid) + if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid) return True; fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); @@ -2246,8 +2246,8 @@ static BOOL current_user_in_group(gid_t gid) { int i; - for (i = 0; i < current_user.ngroups; i++) { - if (current_user.groups[i] == gid) { + for (i = 0; i < current_user.ut.ngroups; i++) { + if (current_user.ut.groups[i] == gid) { return True; } } @@ -3026,7 +3026,7 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_ &se_restore); /* Case (2) */ - if ( ( has_take_ownership_priv && ( uid == current_user.uid ) ) || + if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) || /* Case (3) */ ( has_restore_priv ) ) { @@ -3056,7 +3056,7 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_ and also copes with the case where the SID in a take ownership ACL is a local SID on the users workstation */ - uid = current_user.uid; + uid = current_user.ut.uid; become_root(); /* Keep the current file gid the same. */ @@ -3136,7 +3136,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) * the file. */ - if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) { + if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) { DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); @@ -3960,12 +3960,12 @@ refusing write due to mask.\n", fname)); break; case SMB_ACL_USER: { - /* Check against current_user.uid. */ + /* Check against current_user.ut.uid. */ uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); if (puid == NULL) { goto check_stat; } - if (current_user.uid == *puid) { + if (current_user.ut.uid == *puid) { /* We have a uid match but we must ensure we have seen the acl mask. */ ret = have_write; DEBUG(10,("check_posix_acl_group_write: file %s \ @@ -4130,13 +4130,13 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) if (!S_ISDIR(sbuf.st_mode)) { return False; } - if (current_user.uid == 0 || conn->admin_user) { + if (current_user.ut.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } /* Check primary owner write access. */ - if (current_user.uid == sbuf.st_uid) { + if (current_user.ut.uid == sbuf.st_uid) { return (sbuf.st_mode & S_IWUSR) ? True : False; } @@ -4152,7 +4152,7 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) * for bug #3348. Don't assume owning sticky bit * directory means write access allowed. */ - if (current_user.uid != sbuf_file.st_uid) { + if (current_user.ut.uid != sbuf_file.st_uid) { return False; } } @@ -4178,7 +4178,7 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST { int ret; - if (current_user.uid == 0 || conn->admin_user) { + if (current_user.ut.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } @@ -4191,7 +4191,7 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST } /* Check primary owner write access. */ - if (current_user.uid == psbuf->st_uid) { + if (current_user.ut.uid == psbuf->st_uid) { return (psbuf->st_mode & S_IWUSR) ? True : False; } diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 69c71c74b59..89b98be1e77 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1386,7 +1386,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (fattr & aDIR) { DEBUG(3,("attempt to open a directory %s\n",fname)); - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBopen); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1510,13 +1510,13 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) { fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_DISK_FULL); } retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size); if (retval < 0) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBwrite); return ERROR_NT(NT_STATUS_DISK_FULL); } @@ -1526,7 +1526,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt fattr = dos_mode(conn,fname,&sbuf); mtime = sbuf.st_mtime; if (fattr & aDIR) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); END_PROFILE(SMBopenX); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1845,7 +1845,7 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, set_saved_ntstatus(NT_STATUS_OK); return NT_STATUS_ACCESS_DENIED; } - close_file(fsp,False); + close_file(fsp,NORMAL_CLOSE); return NT_STATUS_OK; } @@ -1938,7 +1938,7 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b set_saved_ntstatus(NT_STATUS_OK); return NT_STATUS_ACCESS_DENIED; } - close_file(fsp,False); + close_file(fsp,NORMAL_CLOSE); } return NT_STATUS_OK; } @@ -3267,7 +3267,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * Special case - close NT SMB directory handle. */ DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum)); - close_file(fsp,True); + close_file(fsp,NORMAL_CLOSE); } else { /* * Close ordinary file. @@ -3295,7 +3295,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * a disk full error. If not then it was probably an I/O error. */ - if((close_err = close_file(fsp,True)) != 0) { + if((close_err = close_file(fsp,NORMAL_CLOSE)) != 0) { errno = close_err; END_PROFILE(SMBclose); return (UNIXERROR(ERRHRD,ERRgeneral)); @@ -3356,7 +3356,7 @@ int reply_writeclose(connection_struct *conn, if (numtowrite) { DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n", fsp->fsp_name )); - close_err = close_file(fsp,True); + close_err = close_file(fsp,NORMAL_CLOSE); } DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n", @@ -3596,7 +3596,7 @@ int reply_printclose(connection_struct *conn, DEBUG(3,("printclose fd=%d fnum=%d\n", fsp->fh->fd,fsp->fnum)); - close_err = close_file(fsp,True); + close_err = close_file(fsp,NORMAL_CLOSE); if(close_err != 0) { errno = close_err; @@ -4746,7 +4746,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, NULL); if (!fsp2) { - close_file(fsp1,False); + close_file(fsp1,ERROR_CLOSE); return(False); } @@ -4765,7 +4765,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size); } - close_file(fsp1,False); + close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime); @@ -4776,7 +4776,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, * Thus we don't look at the error return from the * close of fsp1. */ - *err_ret = close_file(fsp2,False); + *err_ret = close_file(fsp2,NORMAL_CLOSE); return(ret == (SMB_OFF_T)src_sbuf.st_size); } diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c index a5411b94a17..fc6a8589747 100644 --- a/source/smbd/sec_ctx.c +++ b/source/smbd/sec_ctx.c @@ -23,10 +23,7 @@ extern struct current_user current_user; struct sec_ctx { - uid_t uid; - uid_t gid; - int ngroups; - gid_t *groups; + UNIX_USER_TOKEN ut; NT_USER_TOKEN *token; }; @@ -216,10 +213,10 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid) prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1]; - SAFE_FREE(prev_ctx_p->groups); - prev_ctx_p->ngroups = 0; + SAFE_FREE(prev_ctx_p->ut.groups); + prev_ctx_p->ut.ngroups = 0; - get_current_groups(gid, &prev_ctx_p->ngroups, &prev_ctx_p->groups); + get_current_groups(gid, &prev_ctx_p->ut.ngroups, &prev_ctx_p->ut.groups); done: unbecome_root(); @@ -249,26 +246,26 @@ BOOL push_sec_ctx(void) ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - ctx_p->uid = geteuid(); - ctx_p->gid = getegid(); + ctx_p->ut.uid = geteuid(); + ctx_p->ut.gid = getegid(); DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", - (unsigned int)ctx_p->uid, (unsigned int)ctx_p->gid, sec_ctx_stack_ndx )); + (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx )); ctx_p->token = dup_nt_token(sec_ctx_stack[sec_ctx_stack_ndx-1].token); - ctx_p->ngroups = sys_getgroups(0, NULL); + ctx_p->ut.ngroups = sys_getgroups(0, NULL); - if (ctx_p->ngroups != 0) { - if (!(ctx_p->groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ngroups))) { + if (ctx_p->ut.ngroups != 0) { + if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) { DEBUG(0, ("Out of memory in push_sec_ctx()\n")); delete_nt_token(&ctx_p->token); return False; } - sys_getgroups(ctx_p->ngroups, ctx_p->groups); + sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups); } else { - ctx_p->groups = NULL; + ctx_p->ut.groups = NULL; } return True; @@ -296,28 +293,28 @@ void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN sys_setgroups(ngroups, groups); #endif - ctx_p->ngroups = ngroups; + ctx_p->ut.ngroups = ngroups; - SAFE_FREE(ctx_p->groups); + SAFE_FREE(ctx_p->ut.groups); if (token && (token == ctx_p->token)) smb_panic("DUPLICATE_TOKEN"); delete_nt_token(&ctx_p->token); - ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups); + ctx_p->ut.groups = memdup(groups, sizeof(gid_t) * ngroups); ctx_p->token = dup_nt_token(token); become_id(uid, gid); - ctx_p->uid = uid; - ctx_p->gid = gid; + ctx_p->ut.uid = uid; + ctx_p->ut.gid = gid; /* Update current_user stuff */ - current_user.uid = uid; - current_user.gid = gid; - current_user.ngroups = ngroups; - current_user.groups = groups; + current_user.ut.uid = uid; + current_user.ut.gid = gid; + current_user.ut.ngroups = ngroups; + current_user.ut.groups = groups; current_user.nt_user_token = ctx_p->token; } @@ -352,11 +349,11 @@ BOOL pop_sec_ctx(void) /* Clear previous user info */ - ctx_p->uid = (uid_t)-1; - ctx_p->gid = (gid_t)-1; + ctx_p->ut.uid = (uid_t)-1; + ctx_p->ut.gid = (gid_t)-1; - SAFE_FREE(ctx_p->groups); - ctx_p->ngroups = 0; + SAFE_FREE(ctx_p->ut.groups); + ctx_p->ut.ngroups = 0; delete_nt_token(&ctx_p->token); @@ -369,17 +366,17 @@ BOOL pop_sec_ctx(void) prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; #ifdef HAVE_SETGROUPS - sys_setgroups(prev_ctx_p->ngroups, prev_ctx_p->groups); + sys_setgroups(prev_ctx_p->ut.ngroups, prev_ctx_p->ut.groups); #endif - become_id(prev_ctx_p->uid, prev_ctx_p->gid); + become_id(prev_ctx_p->ut.uid, prev_ctx_p->ut.gid); /* Update current_user stuff */ - current_user.uid = prev_ctx_p->uid; - current_user.gid = prev_ctx_p->gid; - current_user.ngroups = prev_ctx_p->ngroups; - current_user.groups = prev_ctx_p->groups; + current_user.ut.uid = prev_ctx_p->ut.uid; + current_user.ut.gid = prev_ctx_p->ut.gid; + current_user.ut.ngroups = prev_ctx_p->ut.ngroups; + current_user.ut.groups = prev_ctx_p->ut.groups; current_user.nt_user_token = prev_ctx_p->token; DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", @@ -400,26 +397,26 @@ void init_sec_ctx(void) memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH); for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) { - sec_ctx_stack[i].uid = (uid_t)-1; - sec_ctx_stack[i].gid = (gid_t)-1; + sec_ctx_stack[i].ut.uid = (uid_t)-1; + sec_ctx_stack[i].ut.gid = (gid_t)-1; } /* Initialise first level of stack. It is the current context */ ctx_p = &sec_ctx_stack[0]; - ctx_p->uid = geteuid(); - ctx_p->gid = getegid(); + ctx_p->ut.uid = geteuid(); + ctx_p->ut.gid = getegid(); - get_current_groups(ctx_p->gid, &ctx_p->ngroups, &ctx_p->groups); + get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups); ctx_p->token = NULL; /* Maps to guest user. */ /* Initialise current_user global */ - current_user.uid = ctx_p->uid; - current_user.gid = ctx_p->gid; - current_user.ngroups = ctx_p->ngroups; - current_user.groups = ctx_p->groups; + current_user.ut.uid = ctx_p->ut.uid; + current_user.ut.gid = ctx_p->ut.gid; + current_user.ut.ngroups = ctx_p->ut.ngroups; + current_user.ut.groups = ctx_p->ut.groups; /* The conn and vuid are usually taken care of by other modules. We initialise them here. */ diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 8ff219b468c..b8fc2b5b8f1 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -856,7 +856,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i inode = sbuf.st_ino; if (fattr & aDIR) { talloc_destroy(ctx); - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); return(ERROR_DOS(ERRDOS,ERRnoaccess)); } @@ -864,7 +864,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i status = set_ea(conn, fsp, fname, ea_list); talloc_destroy(ctx); if (!NT_STATUS_IS_OK(status)) { - close_file(fsp,False); + close_file(fsp,ERROR_CLOSE); return ERROR_NT(status); } } @@ -2355,7 +2355,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned fsp.fnum = -1; /* access check */ - if (current_user.uid != 0) { + if (current_user.ut.uid != 0) { DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)),conn->user)); return ERROR_DOS(ERRDOS,ERRnoaccess); @@ -2530,7 +2530,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", ZERO_STRUCT(quotas); /* access check */ - if ((current_user.uid != 0)||!CAN_WRITE(conn)) { + if ((current_user.ut.uid != 0)||!CAN_WRITE(conn)) { DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)),conn->user)); return ERROR_DOS(ERRSRV,ERRaccess); @@ -3888,7 +3888,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char new_fsp->fnum, strerror(errno))); ret = -1; } - close_file(new_fsp,True); + close_file(new_fsp,NORMAL_CLOSE); } else { ret = vfs_allocate_file_space(fsp, allocation_size); if (SMB_VFS_FSTAT(fsp,fd,&new_sbuf) != 0) { @@ -3951,7 +3951,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char } /* The set is across all open files on this dev/inode pair. */ - if (!set_delete_on_close(fsp, delete_on_close)) { + if (!set_delete_on_close(fsp, delete_on_close, ¤t_user.ut)) { return ERROR_NT(NT_STATUS_ACCESS_DENIED); } @@ -4416,7 +4416,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", return(UNIXERROR(ERRDOS,ERRbadpath)); } ret = vfs_set_filelen(new_fsp, size); - close_file(new_fsp,True); + close_file(new_fsp,NORMAL_CLOSE); } else { ret = vfs_set_filelen(fsp, size); } diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 9db3d97ab2d..d419720c33e 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -30,18 +30,18 @@ extern struct current_user current_user; gid_t get_current_user_gid_first(int *piterator) { *piterator = 0; - return current_user.gid; + return current_user.ut.gid; } gid_t get_current_user_gid_next(int *piterator) { gid_t ret; - if (!current_user.groups || *piterator >= current_user.ngroups) { + if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) { return (gid_t)-1; } - ret = current_user.groups[*piterator]; + ret = current_user.ut.groups[*piterator]; (*piterator) += 1; return ret; } @@ -216,12 +216,12 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) */ if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && - (current_user.uid == conn->uid)) { + (current_user.ut.uid == conn->uid)) { DEBUG(4,("change_to_user: Skipping user change - already user\n")); return(True); } else if ((current_user.conn == conn) && (vuser != 0) && (current_user.vuid == vuid) && - (current_user.uid == vuser->uid)) { + (current_user.ut.uid == vuser->uid)) { DEBUG(4,("change_to_user: Skipping user change - already user\n")); return(True); } @@ -237,14 +237,14 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) if (conn->force_user) /* security = share sets this too */ { uid = conn->uid; gid = conn->gid; - current_user.groups = conn->groups; - current_user.ngroups = conn->ngroups; + current_user.ut.groups = conn->groups; + current_user.ut.ngroups = conn->ngroups; token = conn->nt_user_token; } else if (vuser) { uid = conn->admin_user ? 0 : vuser->uid; gid = vuser->gid; - current_user.ngroups = vuser->n_groups; - current_user.groups = vuser->groups; + current_user.ut.ngroups = vuser->n_groups; + current_user.ut.groups = vuser->groups; token = vuser->nt_user_token; } else { DEBUG(2,("change_to_user: Invalid vuid used %d in accessing share %s.\n",vuid, lp_servicename(snum) )); @@ -270,8 +270,8 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) */ int i; - for (i = 0; i < current_user.ngroups; i++) { - if (current_user.groups[i] == conn->gid) { + for (i = 0; i < current_user.ut.ngroups; i++) { + if (current_user.ut.groups[i] == conn->gid) { gid = conn->gid; break; } @@ -288,7 +288,7 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) if (vuser && vuser->guest) is_guest = True; - token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest); + token = create_nt_token(uid, gid, current_user.ut.ngroups, current_user.ut.groups, is_guest); if (!token) { DEBUG(1, ("change_to_user: create_nt_token failed!\n")); return False; @@ -296,7 +296,7 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) must_free_token = True; } - set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token); + set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, token); /* * Free the new token (as set_sec_ctx copies it). @@ -343,8 +343,8 @@ BOOL become_authenticated_pipe_user(pipes_struct *p) if (!push_sec_ctx()) return False; - set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, - p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token); + set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid, + p->pipe_user.ut.ngroups, p->pipe_user.ut.groups, p->pipe_user.nt_user_token); return True; } -- cgit From 5837e5a1bbd30b1d002e6fb2f3f2c6149081d267 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 2 Feb 2006 21:29:49 +0000 Subject: r13294: Fix basic delete on close tests - don't forget to tell the data struct how big the token is... :-). Jeremy. --- source/locking/locking.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index e558c6d74ff..666988b5413 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -558,6 +558,7 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) struct locking_data *data; ssize_t offset; ssize_t sp_len; + uint32 delete_token_size; result.dptr = NULL; result.dsize = 0; @@ -573,10 +574,12 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) } sp_len = strlen(lck->servicepath); + delete_token_size = (lck->delete_token ? + (8 + (lck->delete_token->ngroups*4)) : 0); result.dsize = sizeof(*data) + lck->num_share_modes * sizeof(struct share_mode_entry) + - (lck->delete_token ? (8 + (lck->delete_token->ngroups*4)) : 0) + + delete_token_size + sp_len + 1 + strlen(lck->filename) + 1; result.dptr = talloc_size(lck, result.dsize); @@ -590,10 +593,12 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) data->u.s.num_share_mode_entries = lck->num_share_modes; data->u.s.delete_on_close = lck->delete_on_close; data->u.s.initial_delete_on_close = lck->initial_delete_on_close; - DEBUG(10, ("unparse_share_modes: del: %d, initial del %d, num: %d\n", - data->u.s.delete_on_close, - data->u.s.initial_delete_on_close, - data->u.s.num_share_mode_entries)); + data->u.s.delete_token_size = delete_token_size; + DEBUG(10, ("unparse_share_modes: del: %d, initial del %d, tok = %u, num: %d\n", + data->u.s.delete_on_close, + data->u.s.initial_delete_on_close, + (unsigned int)data->u.s.delete_token_size, + data->u.s.num_share_mode_entries)); memcpy(result.dptr + sizeof(*data), lck->share_modes, sizeof(struct share_mode_entry)*lck->num_share_modes); offset = sizeof(*data) + -- cgit From 4f7ee0f70f2f380d35286817be84561bf7e42c4c Mon Sep 17 00:00:00 2001 From: Lars Müller Date: Thu, 2 Feb 2006 21:34:40 +0000 Subject: r13296: Align trunk with branches/SAMBA_3_0. Add missing '\' in branches/SAMBA_3_0. --- packaging/Debian/debian-unstable/samba-common.dhcp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/Debian/debian-unstable/samba-common.dhcp b/packaging/Debian/debian-unstable/samba-common.dhcp index 38743a4568a..8d1dcab6388 100644 --- a/packaging/Debian/debian-unstable/samba-common.dhcp +++ b/packaging/Debian/debian-unstable/samba-common.dhcp @@ -15,7 +15,7 @@ netbios_setup() { # Nor should we continue if no settings have changed if [ "$new_netbios_name_servers" = "$old_netbios_name_servers" ] \ - && [ "$new_netbios_scope" = "$old_netbios_scope" ] + && [ "$new_netbios_scope" = "$old_netbios_scope" ] \ && [ -f $SAMBA_DHCP_CONF ] then return -- cgit From ff072c8dce4788a83fe206f5c7caab2a20a62eb6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Feb 2006 02:16:35 +0000 Subject: r13299: From testing W2K3 and W2K the delete on close bit seems to be always honored (ie. the file gets deleted) for derectories when set at open time - even though it doesn't show in the qfileinfo call. This is not true of files.... (if anyone from the EU is listening, it's stuff like this that makes CIFS non-documentable :-). Jeremy. --- source/smbd/open.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/smbd/open.c b/source/smbd/open.c index 15e814aae3c..f75bc55b46c 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1973,9 +1973,9 @@ files_struct *open_directory(connection_struct *conn, set_share_mode(lck, fsp, 0, NO_OPLOCK); - if ((create_options & FILE_DELETE_ON_CLOSE) && - (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || - info == FILE_WAS_SUPERSEDED)) { + /* For directories the delete on close bit at open time seems + always to be honored on close... See test 19 in Samba4 BASE-DELETE. */ + if (create_options & FILE_DELETE_ON_CLOSE) { status = can_set_delete_on_close(fsp, True, 0); if (!NT_STATUS_IS_OK(status)) { set_saved_ntstatus(status); -- cgit From 835f018ef2901439e738a83ac5c233c767ff20ca Mon Sep 17 00:00:00 2001 From: Lars Müller Date: Fri, 3 Feb 2006 15:39:07 +0000 Subject: r13306: Do not call netbios_setup() if this file is sourced by sh or bash. --- packaging/Debian/debian-unstable/samba-common.dhcp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/Debian/debian-unstable/samba-common.dhcp b/packaging/Debian/debian-unstable/samba-common.dhcp index 8d1dcab6388..c8c4b9e14a8 100644 --- a/packaging/Debian/debian-unstable/samba-common.dhcp +++ b/packaging/Debian/debian-unstable/samba-common.dhcp @@ -58,4 +58,8 @@ netbios_setup() { fi } -netbios_setup +# Only call netbios_setup if we're not sourced. +case "$0" in + *bin/sh|*bin/bash) : ;; + *) netbios_setup ;; +esac -- cgit From f8c735fe578f07b0b663a4f7e79e6f61bca211c0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 3 Feb 2006 19:24:52 +0000 Subject: r13309: If the sid in the winbind name2sid cache is not valid (NT_STATUS_NONE_MAPPED), we have S-0-0 as a SID in the cache. This leads to ugly level 0 messages from string_to_sid. Avoid them. Volker --- source/nsswitch/winbindd_cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c index 1d047b8356f..9ecfb1ff6ed 100644 --- a/source/nsswitch/winbindd_cache.c +++ b/source/nsswitch/winbindd_cache.c @@ -960,8 +960,10 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, if (!centry) goto do_query; *type = (enum SID_NAME_USE)centry_uint32(centry); - centry_sid(centry, sid); status = centry->status; + if (NT_STATUS_IS_OK(status)) { + centry_sid(centry, sid); + } DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n", domain->name, get_friendly_nt_error_msg(status) )); -- cgit From ae7207c5a8208acd5935e338aa2473177d4f52f0 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 3 Feb 2006 21:19:24 +0000 Subject: r13310: first round of server affinity patches for winbindd & net ads join --- source/include/smb.h | 8 -- source/lib/gencache.c | 20 ++- source/libads/ldap.c | 4 + source/libsmb/cliconnect.c | 12 +- source/libsmb/namequery.c | 323 +++++++++++++++++++++++++++--------------- source/libsmb/namequery_dc.c | 28 ---- source/nsswitch/winbindd_cm.c | 70 +++++---- source/passdb/secrets.c | 29 ---- 8 files changed, 275 insertions(+), 219 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index b8211aac45c..3a6f68b9ecc 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -238,14 +238,6 @@ typedef struct nttime_info { #define MAX_HOURS_LEN 32 -/* - * window during which we must talk to the PDC to avoid - * sam sync delays; expressed in seconds (15 minutes is the - * default period for SAM replication under Windows NT 4.0 - */ -#define SAM_SYNC_WINDOW 900 - - #ifndef MAXSUBAUTHS #define MAXSUBAUTHS 15 /* max sub authorities in a SID */ #endif diff --git a/source/lib/gencache.c b/source/lib/gencache.c index fd44616270c..89badcd4f97 100644 --- a/source/lib/gencache.c +++ b/source/lib/gencache.c @@ -268,7 +268,7 @@ BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) SAFE_FREE(entry_buf); DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, " - "timeout = %s\n", t > time(NULL) ? "valid" : + "timeout = %s", t > time(NULL) ? "valid" : "expired", keystr, v, ctime(&t))); if (valstr) @@ -281,20 +281,18 @@ BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) return t > time(NULL); - } else { - SAFE_FREE(databuf.dptr); + } - if (valstr) - *valstr = NULL; + SAFE_FREE(databuf.dptr); - if (timeout) - timeout = NULL; + if (valstr) + *valstr = NULL; + if (timeout) + timeout = NULL; - DEBUG(10, ("Cache entry with key = %s couldn't be found\n", - keystr)); + DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr)); - return False; - } + return False; } diff --git a/source/libads/ldap.c b/source/libads/ldap.c index dc93bd556c7..e503da62a47 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -136,6 +136,10 @@ BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port) ads->ldap_port = port; ads->ldap_ip = *interpret_addr2(srv); free(srv); + + /* cache the successful connection */ + + saf_store( ads->server.workgroup, server ); return True; } diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index ac7d1b1650c..7c15c8d19f2 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -865,14 +865,16 @@ BOOL cli_session_setup(struct cli_state *cli, DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status))); return False; } - return True; + } else { + /* otherwise do a NT1 style session setup */ + if ( !cli_session_setup_nt1(cli, user, pass, passlen, ntpass, ntpasslen, workgroup) ) { + DEBUG(3,("cli_session_setup: NT1 session setup failed!\n")); + return False; + } } - /* otherwise do a NT1 style session setup */ + return True; - return cli_session_setup_nt1(cli, user, - pass, passlen, ntpass, ntpasslen, - workgroup); } /**************************************************************************** diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c index 28b89db9087..0986e7f29a9 100644 --- a/source/libsmb/namequery.c +++ b/source/libsmb/namequery.c @@ -24,6 +24,94 @@ /* nmbd.c sets this to True. */ BOOL global_in_nmbd = False; + +/**************************** + * SERVER AFFINITY ROUTINES * + ****************************/ + + /* Server affinity is the concept of preferring the last domain + controller with whom you had a successful conversation */ + +/**************************************************************************** +****************************************************************************/ +#define SAFKEY_FMT "SAF/DOMAIN/%s" +#define SAF_TTL 900 + +static char *saf_key(const char *domain) +{ + char *keystr; + + asprintf( &keystr, SAFKEY_FMT, strupper_static(domain) ); + + return keystr; +} + +/**************************************************************************** +****************************************************************************/ + +BOOL saf_store( const char *domain, const char *servername ) +{ + char *key; + time_t expire; + BOOL ret = False; + + if ( !domain || !servername ) { + DEBUG(2,("saf_store: Refusing to store empty domain or servername!\n")); + return False; + } + + if ( !gencache_init() ) + return False; + + key = saf_key( domain ); + expire = time( NULL ) + SAF_TTL; + + + DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%d]\n", + domain, servername, expire )); + + ret = gencache_set( key, servername, expire ); + + SAFE_FREE( key ); + + return ret; +} + +/**************************************************************************** +****************************************************************************/ + +char *saf_fetch( const char *domain ) +{ + char *server = NULL; + time_t timeout; + BOOL ret = False; + char *key = NULL; + + if ( !domain ) { + DEBUG(2,("saf_fetch: Empty domain name!\n")); + return NULL; + } + + if ( !gencache_init() ) + return False; + + key = saf_key( domain ); + + ret = gencache_get( key, &server, &timeout ); + + SAFE_FREE( key ); + + if ( !ret ) { + DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n", domain )); + } else { + DEBUG(5,("saf_fetch: Returning \"%s\" for \"%s\" domain\n", + server, domain )); + } + + return server; +} + + /**************************************************************************** Generate a random trn_id. ****************************************************************************/ @@ -1261,6 +1349,18 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only, int *ordered) { fstring resolve_order; + char *saf_servername; + pstring pserver; + const char *p; + char *port_str; + int port; + fstring name; + int num_addresses = 0; + int local_count, i, j; + struct ip_service *return_iplist = NULL; + struct ip_service *auto_ip_list = NULL; + BOOL done_auto_lookup = False; + int auto_count = 0; /* if we are restricted to solely using DNS for looking up a domain controller, make sure that host lookups @@ -1277,148 +1377,145 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, fstrcpy( resolve_order, "NULL" ); } - *ordered = False; - - /* If it's our domain then use the 'password server' parameter. */ - + + /* fetch the server we have affinity for. Add the + 'password server' list to a search for our domain controllers */ + + saf_servername = saf_fetch( domain ); + if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) { - const char *p; - char *pserver = lp_passwordserver(); /* UNIX charset. */ - char *port_str; - int port; - fstring name; - int num_addresses = 0; - int local_count, i, j; - struct ip_service *return_iplist = NULL; - struct ip_service *auto_ip_list = NULL; - BOOL done_auto_lookup = False; - int auto_count = 0; - + pstr_sprintf( pserver, "%s, %s", + saf_servername ? saf_servername : "", + lp_passwordserver() ); + } else { + pstr_sprintf( pserver, "%s, *", + saf_servername ? saf_servername : "" ); + } - if (!*pserver) - return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + SAFE_FREE( saf_servername ); - p = pserver; - - /* - * if '*' appears in the "password server" list then add - * an auto lookup to the list of manually configured - * DC's. If any DC is listed by name, then the list should be - * considered to be ordered - */ - - while (next_token(&p,name,LIST_SEP,sizeof(name))) { - if (strequal(name, "*")) { - if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_order) ) - num_addresses += auto_count; - done_auto_lookup = True; - DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count)); - } else { - num_addresses++; - } + /* if we are starting from scratch, just lookup DOMAIN<0x1c> */ + + if ( !*pserver ) { + DEBUG(10,("get_dc_list: no preferred domain controllers.\n")); + return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + } + + DEBUG(3,("get_dc_list: preferred server list: \"%s\"\n", pserver )); + + /* + * if '*' appears in the "password server" list then add + * an auto lookup to the list of manually configured + * DC's. If any DC is listed by name, then the list should be + * considered to be ordered + */ + + p = pserver; + while (next_token(&p,name,LIST_SEP,sizeof(name))) { + if (strequal(name, "*")) { + if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_order) ) + num_addresses += auto_count; + done_auto_lookup = True; + DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count)); + } else { + num_addresses++; } + } - /* if we have no addresses and haven't done the auto lookup, then - just return the list of DC's */ + /* if we have no addresses and haven't done the auto lookup, then + just return the list of DC's. Or maybe we just failed. */ - if ( (num_addresses == 0) && !done_auto_lookup ) { + if ( (num_addresses == 0) ) { + if ( !done_auto_lookup ) { return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); - } - - /* maybe we just failed? */ - - if ( num_addresses == 0 ) { - DEBUG(4,("get_dc_list: no servers found\n")); - return False; - } - - if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) { - DEBUG(3,("get_dc_list: malloc fail !\n")); + } else { + DEBUG(4,("get_dc_list: no servers found\n")); return False; } + } + + if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) { + DEBUG(3,("get_dc_list: malloc fail !\n")); + return False; + } - p = pserver; - local_count = 0; + p = pserver; + local_count = 0; - /* fill in the return list now with real IP's */ + /* fill in the return list now with real IP's */ - while ( (local_count= 4 ) { - DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count, - *ordered ? "":"un")); - DEBUG(4,("get_dc_list: ")); - for ( i=0; i= 4 ) { + DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count, + *ordered ? "":"un")); + DEBUG(4,("get_dc_list: ")); + for ( i=0; idomain, (*cli)->desthost ); + if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) { result = cli_nt_error(*cli); @@ -658,14 +662,6 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, return True; } - if ( is_our_domain - && must_use_pdc(domain->name) - && get_pdc_ip(domain->name, &ip)) - { - if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs)) - return True; - } - /* try standard netbios queries first */ get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False); @@ -752,12 +748,35 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, { TALLOC_CTX *mem_ctx; NTSTATUS result; - + char *saf_servername = saf_fetch( domain->name ); int retries; if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) return NT_STATUS_NO_MEMORY; + /* we have to check the server affinity cache here since + later we selecte a DC based on response time and not preference */ + + if ( saf_servername ) + { + /* convert an ip address to a name */ + if ( is_ipaddress( saf_servername ) ) + { + fstring saf_name; + struct in_addr ip; + + ip = *interpret_addr2( saf_servername ); + dcip_to_name( domain->name, domain->alt_name, &domain->sid, ip, saf_name ); + fstrcpy( domain->dcname, saf_name ); + } + else + { + fstrcpy( domain->dcname, saf_servername ); + } + + SAFE_FREE( saf_servername ); + } + for (retries = 0; retries < 3; retries++) { int fd = -1; @@ -765,27 +784,28 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; - if ((strlen(domain->dcname) > 0) && - NT_STATUS_IS_OK(check_negative_conn_cache( - domain->name, domain->dcname)) && - (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, - 0x20))) { - int dummy; - struct sockaddr_in addrs[2]; - addrs[0] = domain->dcaddr; - addrs[0].sin_port = htons(445); - addrs[1] = domain->dcaddr; - addrs[1].sin_port = htons(139); - if (!open_any_socket_out(addrs, 2, 10000, - &dummy, &fd)) { + if ((strlen(domain->dcname) > 0) + && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname)) + && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20))) + { + struct sockaddr_in *addrs = NULL; + int num_addrs = 0; + int dummy = 0; + + + add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs); + add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs); + + if (!open_any_socket_out(addrs, num_addrs, 10000, &dummy, &fd)) { fd = -1; } } - if ((fd == -1) && - !find_new_dc(mem_ctx, domain, domain->dcname, - &domain->dcaddr, &fd)) + if ((fd == -1) + && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd)) + { break; + } new_conn->cli = NULL; diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index 14896a33400..88dabbd6443 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -821,35 +821,6 @@ void secrets_named_mutex_release(const char *name) DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name )); } -/********************************************************* - Check to see if we must talk to the PDC to avoid sam - sync delays - ********************************************************/ - -BOOL must_use_pdc( const char *domain ) -{ - time_t now = time(NULL); - time_t last_change_time; - unsigned char passwd[16]; - - if ( !secrets_fetch_trust_account_password(domain, passwd, &last_change_time, NULL) ) - return False; - - /* - * If the time the machine password has changed - * was less than about 15 minutes then we need to contact - * the PDC only, as we cannot be sure domain replication - * has yet taken place. Bug found by Gerald (way to go - * Gerald !). JRA. - */ - - if ( now - last_change_time < SAM_SYNC_WINDOW ) - return True; - - return False; - -} - /******************************************************************************* Store a complete AFS keyfile into secrets.tdb. *******************************************************************************/ -- cgit From e24ac859e7964714ed3b543300aadf77955af5bf Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Feb 2006 22:10:37 +0000 Subject: r13314: This code has been causing problems since 1.9.x I think. Remove check_for_pipe() - Volker was completely correct. If it gets re-added it will be in a old open call path, not in the generic code path. Jeremy. --- source/smbd/open.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/source/smbd/open.c b/source/smbd/open.c index f75bc55b46c..4b13e28f8e1 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -73,23 +73,6 @@ int fd_close(struct connection_struct *conn, return fd_close_posix(conn, fsp); } - -/**************************************************************************** - Check a filename for the pipe string. -****************************************************************************/ - -static void check_for_pipe(const char *fname) -{ - /* special case of pipe opens */ - char s[10]; - StrnCpy(s,fname,sizeof(s)-1); - strlower_m(s); - if (strstr(s,"pipe/")) { - DEBUG(3,("Rejecting named pipe open for %s\n",fname)); - set_saved_error_triple(ERRSRV, ERRaccess, NT_STATUS_ACCESS_DENIED); - } -} - /**************************************************************************** Change the ownership of a file to that of the parent directory. Do this by fd if possible. @@ -226,7 +209,6 @@ static BOOL open_file(files_struct *fsp, /* It's a read-only share - fail if we wanted to write. */ if(accmode != O_RDONLY) { DEBUG(3,("Permission denied opening %s\n",fname)); - check_for_pipe(fname); return False; } else if(flags & O_CREAT) { /* We don't want to write - but we must make sure that @@ -292,7 +274,6 @@ static BOOL open_file(files_struct *fsp, DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " "(flags=%d)\n", fname,strerror(errno),local_flags,flags)); - check_for_pipe(fname); return False; } -- cgit From 5831715049f2d460ce42299963a5defdc160891b Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 3 Feb 2006 22:19:41 +0000 Subject: r13316: Let the carnage begin.... Sync with trunk as off r13315 --- source/Makefile.in | 76 +- source/auth/auth.c | 20 +- source/auth/auth_builtin.c | 6 +- source/auth/auth_compat.c | 2 +- source/auth/auth_domain.c | 41 +- source/auth/auth_ntlmssp.c | 10 +- source/auth/auth_rhosts.c | 190 +-- source/auth/auth_sam.c | 43 +- source/auth/auth_script.c | 10 +- source/auth/auth_server.c | 16 +- source/auth/auth_unix.c | 6 +- source/auth/auth_util.c | 1441 ++++++++-------- source/auth/auth_winbind.c | 19 +- source/configure.in | 32 +- source/groupdb/mapping.c | 195 +-- source/include/ads.h | 2 + source/include/auth.h | 29 +- source/include/doserr.h | 1 + source/include/event.h | 31 + source/include/gpo.h | 91 + source/include/idmap.h | 4 +- source/include/includes.h | 11 +- source/include/local.h | 9 + source/include/messages.h | 2 + source/include/nt_status.h | 6 + source/include/passdb.h | 30 +- source/include/rpc_dfs.h | 532 ++++-- source/include/rpc_lsa.h | 56 +- source/include/rpc_netlogon.h | 13 +- source/include/rpc_samr.h | 4 + source/include/secrets.h | 6 +- source/include/smb.h | 70 +- source/include/smbldap.h | 15 +- source/intl/lang_tdb.c | 2 +- source/lib/dummysmbd.c | 9 + source/lib/events.c | 125 ++ source/lib/genrand.c | 4 +- source/lib/messages.c | 15 + source/lib/pam_errors.c | 1 + source/lib/pidfile.c | 6 +- source/lib/readline.c | 4 +- source/lib/secdesc.c | 10 + source/lib/sharesec.c | 308 ++++ source/lib/smbldap.c | 221 ++- source/lib/smbldap_util.c | 92 +- source/lib/system_smbd.c | 91 +- source/lib/username.c | 124 +- source/lib/util.c | 8 +- source/lib/util_file.c | 33 +- source/lib/util_pw.c | 79 +- source/lib/util_sid.c | 5 + source/lib/util_str.c | 99 +- source/lib/util_unistr.c | 14 +- source/libads/gpo.c | 680 ++++++++ source/libads/gpo_util.c | 496 ++++++ source/libads/kerberos.c | 40 +- source/libads/krb5_errs.c | 132 ++ source/libads/krb5_setpw.c | 49 +- source/libads/ldap.c | 223 +++ source/libads/sasl.c | 23 +- source/libmsrpc/cac_lsarpc.c | 14 +- source/libsmb/cliconnect.c | 2 +- source/libsmb/clidfs.c | 22 +- source/libsmb/clientgen.c | 8 +- source/libsmb/clikrb5.c | 171 +- source/libsmb/clilist.c | 6 +- source/libsmb/clispnego.c | 2 +- source/libsmb/conncache.c | 36 +- source/libsmb/errormap.c | 15 + source/libsmb/gpo.c | 167 ++ source/libsmb/libsmbclient.c | 13 +- source/libsmb/passchange.c | 40 +- source/nsswitch/pam_winbind.c | 991 ++++++++--- source/nsswitch/pam_winbind.h | 56 +- source/nsswitch/wb_client.c | 16 +- source/nsswitch/wbinfo.c | 159 +- source/nsswitch/winbindd.c | 14 +- source/nsswitch/winbindd.h | 17 +- source/nsswitch/winbindd_ads.c | 19 +- source/nsswitch/winbindd_cache.c | 858 +++++++++- source/nsswitch/winbindd_cm.c | 26 +- source/nsswitch/winbindd_cred_cache.c | 270 +++ source/nsswitch/winbindd_creds.c | 162 ++ source/nsswitch/winbindd_dual.c | 217 ++- source/nsswitch/winbindd_group.c | 99 +- source/nsswitch/winbindd_misc.c | 17 + source/nsswitch/winbindd_nss.h | 78 +- source/nsswitch/winbindd_pam.c | 1026 +++++++++++- source/nsswitch/winbindd_passdb.c | 172 +- source/nsswitch/winbindd_reconnect.c | 32 + source/nsswitch/winbindd_rpc.c | 69 +- source/nsswitch/winbindd_sid.c | 50 +- source/nsswitch/winbindd_user.c | 8 +- source/nsswitch/winbindd_util.c | 13 +- source/pam_smbpass/pam_smb_auth.c | 8 +- source/pam_smbpass/pam_smb_passwd.c | 6 +- source/pam_smbpass/support.c | 2 +- source/param/loadparm.c | 715 +++++++- source/param/params.c | 2 +- source/passdb/lookup_sid.c | 831 ++++++++-- source/passdb/machine_sid.c | 3 +- source/passdb/passdb.c | 621 ++----- source/passdb/pdb_get_set.c | 12 +- source/passdb/pdb_interface.c | 444 ++++- source/passdb/pdb_ldap.c | 1530 ++++++++++------- source/passdb/pdb_nds.c | 9 +- source/passdb/pdb_smbpasswd.c | 22 +- source/passdb/pdb_tdb.c | 96 +- source/passdb/secrets.c | 164 +- source/passdb/util_builtin.c | 2 +- source/passdb/util_unixsids.c | 94 ++ source/passdb/util_wellknown.c | 15 + source/printing/nt_printing.c | 14 +- source/printing/print_generic.c | 2 +- source/python/py_lsa.c | 4 +- source/rpc_client/cli_dfs.c | 673 ++++++-- source/rpc_client/cli_lsarpc.c | 111 +- source/rpc_client/cli_netlogon.c | 28 +- source/rpc_client/cli_pipe.c | 6 +- source/rpc_client/cli_samr.c | 7 +- source/rpc_parse/parse_dfs.c | 2917 ++++++++++++++++++++++++++++----- source/rpc_parse/parse_lsa.c | 221 ++- source/rpc_parse/parse_net.c | 49 +- source/rpc_parse/parse_prs.c | 29 + source/rpc_parse/parse_rpc.c | 10 - source/rpc_parse/parse_samr.c | 6 +- source/rpc_server/srv_dfs.c | 587 ++++++- source/rpc_server/srv_dfs_nt.c | 406 +++-- source/rpc_server/srv_lsa_nt.c | 256 +-- source/rpc_server/srv_netlog_nt.c | 96 +- source/rpc_server/srv_pipe.c | 5 +- source/rpc_server/srv_pipe_hnd.c | 5 +- source/rpc_server/srv_samr_nt.c | 279 ++-- source/rpc_server/srv_spoolss_nt.c | 20 +- source/rpc_server/srv_srvsvc_nt.c | 208 +-- source/rpcclient/cmd_dfs.c | 111 +- source/rpcclient/cmd_lsarpc.c | 4 +- source/rpcclient/cmd_samr.c | 137 ++ source/sam/idmap.c | 41 +- source/sam/idmap_ad.c | 7 - source/sam/idmap_ldap.c | 271 +-- source/sam/idmap_rid.c | 6 - source/sam/idmap_smbldap.c | 10 - source/sam/idmap_tdb.c | 39 - source/sam/idmap_util.c | 74 - source/script/installman.sh | 5 +- source/script/installswat.sh | 20 +- source/smbd/chgpasswd.c | 13 +- source/smbd/conn.c | 2 +- source/smbd/lanman.c | 2750 +++++++++++++++++-------------- source/smbd/msdfs.c | 8 +- source/smbd/ntquotas.c | 9 +- source/smbd/nttrans.c | 2 +- source/smbd/open.c | 10 +- source/smbd/password.c | 143 +- source/smbd/posix_acls.c | 10 +- source/smbd/process.c | 115 +- source/smbd/sec_ctx.c | 58 +- source/smbd/server.c | 29 +- source/smbd/service.c | 287 +++- source/smbd/sesssetup.c | 30 +- source/smbd/share_access.c | 264 +++ source/smbd/uid.c | 131 +- source/utils/net.c | 27 + source/utils/net.h | 23 + source/utils/net_ads_gpo.c | 436 +++++ source/utils/net_groupmap.c | 38 +- source/utils/net_help.c | 9 +- source/utils/net_lookup.c | 52 + source/utils/net_rpc.c | 557 ++++++- source/utils/net_rpc_rights.c | 55 +- source/utils/net_rpc_samsync.c | 141 +- source/utils/net_rpc_shell.c | 270 +++ source/utils/net_sam.c | 784 +++++++++ source/utils/net_usershare.c | 829 ++++++++++ source/utils/net_util.c | 89 + source/utils/netlookup.c | 209 +++ source/utils/ntlm_auth.c | 6 +- source/utils/pdbedit.c | 10 +- source/utils/smbcacls.c | 2 +- source/utils/smbcontrol.c | 114 +- source/utils/smbcquotas.c | 2 +- source/utils/smbpasswd.c | 24 +- source/web/cgi.c | 10 +- source/web/swat.c | 6 +- 185 files changed, 22346 insertions(+), 7225 deletions(-) create mode 100644 source/include/event.h create mode 100644 source/include/gpo.h create mode 100644 source/lib/events.c create mode 100644 source/lib/sharesec.c create mode 100644 source/libads/gpo.c create mode 100644 source/libads/gpo_util.c create mode 100644 source/libads/krb5_errs.c create mode 100644 source/libsmb/gpo.c create mode 100644 source/nsswitch/winbindd_cred_cache.c create mode 100644 source/nsswitch/winbindd_creds.c create mode 100644 source/passdb/util_unixsids.c create mode 100644 source/smbd/share_access.c create mode 100644 source/utils/net_ads_gpo.c create mode 100644 source/utils/net_rpc_shell.c create mode 100644 source/utils/net_sam.c create mode 100644 source/utils/net_usershare.c create mode 100644 source/utils/net_util.c create mode 100644 source/utils/netlookup.c diff --git a/source/Makefile.in b/source/Makefile.in index 6c182a6e41a..281d58f23d0 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -134,7 +134,7 @@ BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \ bin/tdbtool@EXEEXT@ BIN_PROGS3 = bin/smbpasswd@EXEEXT@ bin/rpcclient@EXEEXT@ bin/smbcacls@EXEEXT@ \ bin/profiles@EXEEXT@ bin/ntlm_auth@EXEEXT@ \ - bin/smbcquotas@EXEEXT@ bin/eventlogadm@EXEEXT@ + bin/smbcquotas@EXEEXT@ bin/eventlogadm@EXEEXT@ TORTURE_PROGS = bin/smbtorture@EXEEXT@ bin/msgtest@EXEEXT@ \ bin/masktest@EXEEXT@ bin/locktest@EXEEXT@ \ @@ -207,8 +207,9 @@ LIB_OBJ = $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \ nsswitch/wb_client.o $(WBCOMMON_OBJ) \ lib/pam_errors.o intl/lang_tdb.o \ lib/adt_tree.o lib/gencache.o $(TDB_OBJ) \ - lib/module.o lib/ldap_escape.o @CHARSET_STATIC@ \ - lib/secdesc.o lib/secace.o lib/secacl.o @SOCKWRAP@ + lib/module.o lib/events.o lib/ldap_escape.o @CHARSET_STATIC@ \ + lib/secdesc.o lib/util_seaccess.o lib/secace.o lib/secacl.o @SOCKWRAP@ \ + libads/krb5_errs.o LIB_DUMMY_OBJ = lib/dummysmbd.o lib/dummyroot.o LIB_NONSMBD_OBJ = $(LIB_OBJ) $(LIB_DUMMY_OBJ) @@ -219,7 +220,7 @@ READLINE_OBJ = lib/readline.o # Be sure to include them into your application POPT_LIB_OBJ = lib/popt_common.o -PARAM_OBJ = dynconfig.o param/loadparm.o param/params.o +PARAM_OBJ = dynconfig.o param/loadparm.o param/params.o lib/sharesec.o KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o @@ -244,12 +245,11 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \ libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \ libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \ libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \ - libsmb/clistr.o lib/util_seaccess.o \ - libsmb/cliquota.o libsmb/clifsinfo.o libsmb/clidfs.o \ + libsmb/clistr.o libsmb/cliquota.o libsmb/clifsinfo.o libsmb/clidfs.o \ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \ libsmb/clioplock.o $(ERRORMAP_OBJ) libsmb/clirap2.o \ $(DOSERR_OBJ) \ - $(RPC_PARSE_OBJ1) $(LIBSAMBA_OBJ) $(LIBNMB_OBJ) + $(RPC_PARSE_OBJ1) $(LIBSAMBA_OBJ) $(LIBNMB_OBJ) LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \ rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \ @@ -324,7 +324,7 @@ PASSDB_GET_SET_OBJ = passdb/pdb_get_set.o PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \ passdb/util_wellknown.o passdb/util_builtin.o passdb/pdb_compat.o \ - passdb/lookup_sid.o \ + passdb/util_unixsids.o passdb/lookup_sid.o \ passdb/login_cache.o @PDB_STATIC@ passdb/pdb_sql.o \ lib/system_smbd.o lib/account_pol.o lib/privileges.o @@ -390,7 +390,8 @@ BUILDOPT_OBJ = smbd/build_options.o SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/utmp.o smbd/session.o \ - smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \ + smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o \ + smbd/share_access.o smbd/fileio.o \ smbd/ipc.o smbd/lanman.o smbd/negprot.o \ smbd/message.o smbd/nttrans.o smbd/pipes.o \ smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \ @@ -462,12 +463,13 @@ SMBSH_OBJ = smbwrapper/smbsh.o smbwrapper/shared.o \ STATUS_OBJ = utils/status.o $(LOCKING_OBJ) $(PARAM_OBJ) \ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \ - $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(ERRORMAP_OBJ) + $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(ERRORMAP_OBJ) $(RPC_PARSE_OBJ1) \ + $(DOSERR_OBJ) SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \ - $(SECRETS_OBJ) $(LIBSAMBA_OBJ) \ + $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) \ $(PRINTBASE_OBJ) $(ERRORMAP_OBJ) SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \ @@ -476,16 +478,16 @@ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \ TESTPARM_OBJ = utils/testparm.o \ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \ - $(SECRETS_OBJ) $(LIBSAMBA_OBJ) + $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSCHANGE_OBJ) $(PARAM_OBJ) $(SECRETS_OBJ) \ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ)\ - $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \ + $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(RPC_PARSE_OBJ) $(LIBMSRPC_OBJ) PDBEDIT_OBJ = utils/pdbedit.o $(PARAM_OBJ) $(PASSDB_OBJ) $(LIBSAMBA_OBJ) \ $(LIB_NONSMBD_OBJ) $(GROUPDB_OBJ) $(SECRETS_OBJ) \ - $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) libsmb/asn1.o + $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) libsmb/asn1.o $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) SMBGET_OBJ = utils/smbget.o $(POPT_LIB_OBJ) $(LIBSMBCLIENT_OBJ) @@ -504,9 +506,12 @@ RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \ $(LIBADS_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) -PAM_WINBIND_PICOBJ = nsswitch/pam_winbind.@PICSUFFIX@ \ - nsswitch/wb_common.@PICSUFFIX@ lib/replace1.@PICSUFFIX@ \ - lib/snprintf.@PICSUFFIX@ +PAM_WINBIND_OBJ = nsswitch/pam_winbind.o \ + $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(RPC_PARSE_OBJ1) \ + $(LIBSAMBA_OBJ) $(DOSERR_OBJ) + +PAM_WINBIND_PICOBJ = $(PAM_WINBIND_OBJ:.o=.@PICSUFFIX@) + SMBW_OBJ1 = smbwrapper/smbw.o \ smbwrapper/smbw_dir.o smbwrapper/smbw_stat.o \ @@ -561,7 +566,9 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \ utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \ utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \ utils/net_status.o utils/net_rpc_printer.o utils/net_rpc_rights.o \ - utils/net_rpc_service.o utils/net_rpc_registry.o + utils/net_rpc_service.o utils/net_rpc_registry.o utils/net_usershare.o \ + utils/netlookup.o utils/net_sam.o utils/net_rpc_shell.o \ + utils/net_util.o NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ @@ -569,7 +576,7 @@ NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(LIBMSRPC_OBJ) $(IDMAP_OBJ) \ $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \ - $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(REGFIO_OBJ) + $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(REGFIO_OBJ) $(READLINE_OBJ) CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ) @@ -581,8 +588,9 @@ MNT_OBJ = client/smbmnt.o lib/replace.o $(VERSION_OBJ) $(SNPRINTF_OBJ) UMOUNT_OBJ = client/smbumount.o -NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) \ - $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(SECRETS_OBJ) $(LIBSAMBA_OBJ) +NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) \ + $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(SECRETS_OBJ) $(LIBSAMBA_OBJ) \ + SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \ torture/denytest.o torture/mangle_test.o @@ -625,11 +633,12 @@ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \ EVTLOGADM_OBJ0 = utils/eventlogadm.o EVTLOGADM_OBJ = $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(REGOBJS_OBJ) \ - $(ERRORMAP_OBJ) $(RPC_PARSE_OBJ0) $(LIBSAMBA_OBJ) $(DOSERR_OBJ) \ + $(ERRORMAP_OBJ) $(RPC_PARSE_OBJ1) $(LIBSAMBA_OBJ) $(DOSERR_OBJ) \ registry/reg_eventlog.o rpc_server/srv_eventlog_lib.o registry/reg_util.o \ registry/reg_db.o -TALLOCTORT_OBJ = lib/talloctort.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) libsmb/nterr.o +TALLOCTORT_OBJ = lib/talloctort.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ + $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) $(LIBSAMBA_OBJ) RPCTORTURE_OBJ = torture/rpctorture.o \ rpcclient/display.o \ @@ -699,7 +708,9 @@ WINBINDD_OBJ1 = \ nsswitch/winbindd_ads.o \ nsswitch/winbindd_passdb.o \ nsswitch/winbindd_dual.o \ - nsswitch/winbindd_async.o + nsswitch/winbindd_async.o \ + nsswitch/winbindd_creds.o \ + nsswitch/winbindd_cred_cache.o WINBINDD_OBJ = \ $(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ @@ -708,10 +719,11 @@ WINBINDD_OBJ = \ $(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \ $(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \ $(DCUTIL_OBJ) $(IDMAP_OBJ) \ - $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) + $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \ + $(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ - $(SECRETS_OBJ) $(POPT_LIB_OBJ) $(AFS_SETTOKEN_OBJ) + $(SECRETS_OBJ) $(POPT_LIB_OBJ) $(AFS_SETTOKEN_OBJ) $(RPC_PARSE_OBJ1) $(DOSERR_OBJ) WINBIND_NSS_OBJ = $(WBCOMMON_OBJ) lib/replace1.o @WINBIND_NSS_EXTRA_OBJS@ @@ -731,7 +743,7 @@ NTLM_AUTH_OBJ1 = utils/ntlm_auth.o utils/ntlm_auth_diagnostics.o NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \ libsmb/asn1.o libsmb/spnego.o libsmb/clikrb5.o libads/kerberos.o \ libads/kerberos_verify.o $(SECRETS_OBJ) $(SERVER_MUTEX_OBJ) \ - libads/authdata.o $(RPC_PARSE_OBJ0) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ + libads/authdata.o $(RPC_PARSE_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ $(SMBLDAP_OBJ) $(DOSERR_OBJ) rpc_parse/parse_net.o ###################################################################### @@ -781,7 +793,7 @@ modules: SHOWFLAGS proto_exists $(MODULES) cac: SHOWFLAGS bin/libmsrpc.@SHLIBEXT@ bin/libmsrpc.a -everything: all libsmbclient debug2html smbfilter talloctort modules torture eventlogadm \ +everything: all libsmbclient debug2html smbfilter talloctort modules torture \ $(EVERYTHING_PROGS) .SUFFIXES: @@ -908,7 +920,7 @@ bin/smbctool@EXEEXT@: $(TOOL_OBJ) @BUILD_POPT@ bin/.dummy bin/net@EXEEXT@: $(NET_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(NET_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) $(PASSDB_LIBS) + @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(NET_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) $(PASSDB_LIBS) $(TERMLDFLAGS) $(TERMLIBS) bin/profiles@EXEEXT@: $(PROFILES_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @@ -949,10 +961,10 @@ bin/smbtree@EXEEXT@: $(SMBTREE_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(SMBTREE_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) -bin/smbpasswd@EXEEXT@: $(SMBPASSWD_OBJ) bin/.dummy +bin/smbpasswd@EXEEXT@: $(SMBPASSWD_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(SMBPASSWD_OBJ) $(LDFLAGS) $(PASSDB_LIBS) \ - $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + $(DYNEXP) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) bin/pdbedit@EXEEXT@: $(PDBEDIT_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @@ -1180,7 +1192,7 @@ bin/winbindd@EXEEXT@: $(WINBINDD_OBJ) @BUILD_POPT@ bin/.dummy nsswitch/pam_winbind.@SHLIBEXT@: $(PAM_WINBIND_PICOBJ) bin/.dummy @echo "Linking $@" @$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_WINBIND_PICOBJ) \ - @SONAMEFLAG@`basename $@` -lpam + @SONAMEFLAG@`basename $@` $(LIBS) -lpam bin/rhosts.@SHLIBEXT@: $(AUTH_RHOSTS_OBJ:.o=.@PICSUFFIX@) @echo "Building plugin $@" diff --git a/source/auth/auth.c b/source/auth/auth.c index df7d6fc9c60..6dc30383d5d 100644 --- a/source/auth/auth.c +++ b/source/auth/auth.c @@ -216,10 +216,10 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, return NT_STATUS_LOGON_FAILURE; DEBUG(3, ("check_ntlm_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", - user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str)); + user_info->client_domain, user_info->smb_name, user_info->wksta_name)); DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n", - user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); + user_info->domain, user_info->internal_username, user_info->wksta_name)); if (auth_context->challenge.length != 8) { DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n")); @@ -243,14 +243,14 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, #endif /* This needs to be sorted: If it doesn't match, what should we do? */ - if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) + if (!check_domain_match(user_info->smb_name, user_info->domain)) return NT_STATUS_LOGON_FAILURE; for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) { NTSTATUS result; mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, - user_info->domain.str, user_info->smb_name.str); + user_info->domain, user_info->smb_name); result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info); @@ -265,10 +265,10 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, if (NT_STATUS_IS_OK(nt_status)) { DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", - auth_method->name, user_info->smb_name.str)); + auth_method->name, user_info->smb_name)); } else { DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", - auth_method->name, user_info->smb_name.str, nt_errstr(nt_status))); + auth_method->name, user_info->smb_name, nt_errstr(nt_status))); } talloc_destroy(mem_ctx); @@ -302,8 +302,8 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, DEBUG((*server_info)->guest ? 5 : 2, ("check_ntlm_password: %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n", (*server_info)->guest ? "guest " : "", - user_info->smb_name.str, - user_info->internal_username.str, + user_info->smb_name, + user_info->internal_username, unix_username)); } @@ -313,8 +313,8 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, /* failed authentication; check for guest lapping */ DEBUG(2, ("check_ntlm_password: Authentication for user [%s] -> [%s] FAILED with error %s\n", - user_info->smb_name.str, user_info->internal_username.str, - nt_errstr(nt_status))); + user_info->smb_name, user_info->internal_username, + nt_errstr(nt_status))); ZERO_STRUCTP(server_info); return nt_status; diff --git a/source/auth/auth_builtin.c b/source/auth/auth_builtin.c index 96c2221652e..d4d6d49e40c 100644 --- a/source/auth/auth_builtin.c +++ b/source/auth/auth_builtin.c @@ -41,8 +41,8 @@ static NTSTATUS check_guest_security(const struct auth_context *auth_context, /* mark this as 'not for me' */ NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED; - if (!(user_info->internal_username.str - && *user_info->internal_username.str)) { + if (!(user_info->internal_username + && *user_info->internal_username)) { nt_status = make_server_info_guest(server_info); } @@ -84,7 +84,7 @@ static NTSTATUS check_name_to_ntstatus_security(const struct auth_context *auth_ NTSTATUS nt_status; fstring user; long error_num; - fstrcpy(user, user_info->smb_name.str); + fstrcpy(user, user_info->smb_name); if (strnequal("NT_STATUS", user, strlen("NT_STATUS"))) { strupper_m(user); diff --git a/source/auth/auth_compat.c b/source/auth/auth_compat.c index 2ac70d73546..28b9de8d431 100644 --- a/source/auth/auth_compat.c +++ b/source/auth/auth_compat.c @@ -84,7 +84,7 @@ static NTSTATUS pass_check_smb(const char *smb_name, } else { nt_status = check_plaintext_password(smb_name, plaintext_password, &server_info); } - free_server_info(&server_info); + talloc_free(server_info); return nt_status; } diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c index 266851b2292..81ae7c13400 100644 --- a/source/auth/auth_domain.c +++ b/source/auth/auth_domain.c @@ -221,9 +221,9 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx, mem_ctx, user_info->logon_parameters,/* flags such as 'allow workstation logon' */ dc_name, /* server name */ - user_info->smb_name.str, /* user name logging on. */ - user_info->domain.str, /* domain name */ - user_info->wksta_name.str, /* workstation name */ + user_info->smb_name, /* user name logging on. */ + user_info->domain, /* domain name */ + user_info->wksta_name, /* workstation name */ chal, /* 8 byte challenge. */ user_info->lm_resp, /* lanman 24 byte response */ user_info->nt_resp, /* nt 24 byte response */ @@ -237,8 +237,8 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx, if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("domain_client_validate: unable to validate password " "for user %s in domain %s to Domain controller %s. " - "Error was %s.\n", user_info->smb_name.str, - user_info->domain.str, dc_name, + "Error was %s.\n", user_info->smb_name, + user_info->domain, dc_name, nt_errstr(nt_status))); /* map to something more useful */ @@ -247,13 +247,13 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx, } } else { nt_status = make_server_info_info3(mem_ctx, - user_info->internal_username.str, - user_info->smb_name.str, + user_info->internal_username, + user_info->smb_name, domain, server_info, &info3); - netsamlogon_cache_store( user_info->smb_name.str, &info3 ); + netsamlogon_cache_store( user_info->smb_name, &info3 ); } /* Note - once the cli stream is shutdown the mem_ctx used @@ -296,7 +296,7 @@ static NTSTATUS check_ntdomain_security(const struct auth_context *auth_context, * password file. */ - if(strequal(get_global_sam_name(), user_info->domain.str)) { + if(strequal(get_global_sam_name(), user_info->domain)) { DEBUG(3,("check_ntdomain_security: Requested domain was for this machine.\n")); return NT_STATUS_NOT_IMPLEMENTED; } @@ -305,7 +305,7 @@ static NTSTATUS check_ntdomain_security(const struct auth_context *auth_context, if ( !get_dc_name(domain, NULL, dc_name, &dc_ip) ) { DEBUG(5,("check_ntdomain_security: unable to locate a DC for domain %s\n", - user_info->domain.str)); + user_info->domain)); return NT_STATUS_NO_LOGON_SERVERS; } @@ -360,9 +360,9 @@ static NTSTATUS check_trustdomain_security(const struct auth_context *auth_conte * Check that the requested domain is not our own machine name or domain name. */ - if( strequal(get_global_sam_name(), user_info->domain.str)) { + if( strequal(get_global_sam_name(), user_info->domain)) { DEBUG(3,("check_trustdomain_security: Requested domain [%s] was for this machine.\n", - user_info->domain.str)); + user_info->domain)); return NT_STATUS_NOT_IMPLEMENTED; } @@ -371,7 +371,7 @@ static NTSTATUS check_trustdomain_security(const struct auth_context *auth_conte The logic is that if we know nothing about the domain, that user is not known to us and does not exist */ - if ( !is_trusted_domain( user_info->domain.str ) ) + if ( !is_trusted_domain( user_info->domain ) ) return NT_STATUS_NOT_IMPLEMENTED; /* @@ -379,14 +379,17 @@ static NTSTATUS check_trustdomain_security(const struct auth_context *auth_conte * No need to become_root() as secrets_init() is done at startup. */ - if (!secrets_fetch_trusted_domain_password(user_info->domain.str, &trust_password, + if (!secrets_fetch_trusted_domain_password(user_info->domain, &trust_password, &sid, &last_change_time)) { - DEBUG(0, ("check_trustdomain_security: could not fetch trust account password for domain %s\n", user_info->domain.str)); + DEBUG(0, ("check_trustdomain_security: could not fetch trust " + "account password for domain %s\n", + user_info->domain)); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } #ifdef DEBUG_PASSWORD - DEBUG(100, ("Trust password for domain %s is %s\n", user_info->domain.str, trust_password)); + DEBUG(100, ("Trust password for domain %s is %s\n", user_info->domain, + trust_password)); #endif E_md4hash(trust_password, trust_md4_password); SAFE_FREE(trust_password); @@ -402,15 +405,15 @@ static NTSTATUS check_trustdomain_security(const struct auth_context *auth_conte /* use get_dc_name() for consistency even through we know that it will be a netbios name */ - if ( !get_dc_name(user_info->domain.str, NULL, dc_name, &dc_ip) ) { + if ( !get_dc_name(user_info->domain, NULL, dc_name, &dc_ip) ) { DEBUG(5,("check_trustdomain_security: unable to locate a DC for domain %s\n", - user_info->domain.str)); + user_info->domain)); return NT_STATUS_NO_LOGON_SERVERS; } nt_status = domain_client_validate(mem_ctx, user_info, - user_info->domain.str, + user_info->domain, (uchar *)auth_context->challenge.data, server_info, dc_name, diff --git a/source/auth/auth_ntlmssp.c b/source/auth/auth_ntlmssp.c index 2fef8f1e9b5..2bf86860cc1 100644 --- a/source/auth/auth_ntlmssp.c +++ b/source/auth/auth_ntlmssp.c @@ -115,6 +115,14 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } + + nt_status = create_local_token(auth_ntlmssp_state->server_info); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("create_local_token failed\n")); + return nt_status; + } + if (auth_ntlmssp_state->server_info->user_session_key.length) { DEBUG(10, ("Got NT session key of length %u\n", (unsigned int)auth_ntlmssp_state->server_info->user_session_key.length)); @@ -179,7 +187,7 @@ void auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state) ((*auth_ntlmssp_state)->auth_context->free)(&(*auth_ntlmssp_state)->auth_context); } if ((*auth_ntlmssp_state)->server_info) { - free_server_info(&(*auth_ntlmssp_state)->server_info); + talloc_free((*auth_ntlmssp_state)->server_info); } talloc_destroy(mem_ctx); *auth_ntlmssp_state = NULL; diff --git a/source/auth/auth_rhosts.c b/source/auth/auth_rhosts.c index b561e3d42be..e310fa80fd5 100644 --- a/source/auth/auth_rhosts.c +++ b/source/auth/auth_rhosts.c @@ -60,103 +60,101 @@ static NTSTATUS auth_get_sam_account(const char *user, SAM_ACCOUNT **account) static BOOL check_user_equiv(const char *user, const char *remote, const char *equiv_file) { - int plus_allowed = 1; - char *file_host; - char *file_user; - char **lines = file_lines_load(equiv_file, NULL); - int i; - - DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); - if (! lines) return False; - for (i=0; lines[i]; i++) { - char *buf = lines[i]; - trim_char(buf,' ',' '); - - if (buf[0] != '#' && buf[0] != '\n') - { - BOOL is_group = False; - int plus = 1; - char *bp = buf; - if (strcmp(buf, "NO_PLUS\n") == 0) - { - DEBUG(6, ("check_user_equiv NO_PLUS\n")); - plus_allowed = 0; - } - else { - if (buf[0] == '+') - { - bp++; - if (*bp == '\n' && plus_allowed) - { - /* a bare plus means everbody allowed */ - DEBUG(6, ("check_user_equiv everybody allowed\n")); - file_lines_free(lines); - return True; - } - } - else if (buf[0] == '-') - { - bp++; - plus = 0; - } - if (*bp == '@') - { - is_group = True; - bp++; + int plus_allowed = 1; + char *file_host; + char *file_user; + char **lines = file_lines_load(equiv_file, NULL,0); + int i; + + DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); + if (! lines) { + return False; } - file_host = strtok(bp, " \t\n"); - file_user = strtok(NULL, " \t\n"); - DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", - file_user ? file_user : "(null)" )); - if (file_host && *file_host) - { - BOOL host_ok = False; + for (i=0; lines[i]; i++) { + char *buf = lines[i]; + trim_char(buf,' ',' '); + + if (buf[0] != '#' && buf[0] != '\n') { + BOOL is_group = False; + int plus = 1; + char *bp = buf; + + if (strcmp(buf, "NO_PLUS\n") == 0) { + DEBUG(6, ("check_user_equiv NO_PLUS\n")); + plus_allowed = 0; + } else { + if (buf[0] == '+') { + bp++; + if (*bp == '\n' && plus_allowed) { + /* a bare plus means everbody allowed */ + DEBUG(6, ("check_user_equiv everybody allowed\n")); + file_lines_free(lines); + return True; + } + } else if (buf[0] == '-') { + bp++; + plus = 0; + } + if (*bp == '@') { + is_group = True; + bp++; + } + file_host = strtok(bp, " \t\n"); + file_user = strtok(NULL, " \t\n"); + DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", + file_user ? file_user : "(null)" )); + + if (file_host && *file_host) { + BOOL host_ok = False; #if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN) - if (is_group) - { - static char *mydomain = NULL; - if (!mydomain) - yp_get_default_domain(&mydomain); - if (mydomain && innetgr(file_host,remote,user,mydomain)) - host_ok = True; - } + if (is_group) { + static char *mydomain = NULL; + if (!mydomain) { + yp_get_default_domain(&mydomain); + } + if (mydomain && innetgr(file_host,remote,user,mydomain)) { + host_ok = True; + } + } #else - if (is_group) - { - DEBUG(1,("Netgroups not configured\n")); - continue; - } + if (is_group) { + DEBUG(1,("Netgroups not configured\n")); + continue; + } #endif - /* is it this host */ - /* the fact that remote has come from a call of gethostbyaddr - * means that it may have the fully qualified domain name - * so we could look up the file version to get it into - * a canonical form, but I would rather just type it - * in full in the equiv file - */ - if (!host_ok && !is_group && strequal(remote, file_host)) - host_ok = True; - - if (!host_ok) - continue; - - /* is it this user */ - if (file_user == 0 || strequal(user, file_user)) - { - DEBUG(5, ("check_user_equiv matched %s%s %s\n", - (plus ? "+" : "-"), file_host, - (file_user ? file_user : ""))); - file_lines_free(lines); - return (plus ? True : False); - } + /* is it this host */ + /* the fact that remote has come from a call of gethostbyaddr + * means that it may have the fully qualified domain name + * so we could look up the file version to get it into + * a canonical form, but I would rather just type it + * in full in the equiv file + */ + + if (!host_ok && !is_group && strequal(remote, file_host)) { + host_ok = True; + } + + if (!host_ok) { + continue; + } + + /* is it this user */ + if (file_user == 0 || strequal(user, file_user)) { + DEBUG(5, ("check_user_equiv matched %s%s %s\n", + (plus ? "+" : "-"), file_host, + (file_user ? file_user : ""))); + file_lines_free(lines); + return (plus ? True : False); + } + } + } + } } - } - } - } - file_lines_free(lines); - return False; + + file_lines_free(lines); + return False; } /**************************************************************************** @@ -169,7 +167,7 @@ static BOOL check_hosts_equiv(SAM_ACCOUNT *account) char *fname = NULL; fname = lp_hosts_equiv(); - if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(account), &uid))) + if (!sid_to_uid(pdb_get_user_sid(account), &uid)) return False; /* note: don't allow hosts.equiv on root */ @@ -195,7 +193,7 @@ static NTSTATUS check_hostsequiv_security(const struct auth_context *auth_contex NTSTATUS nt_status; SAM_ACCOUNT *account = NULL; if (!NT_STATUS_IS_OK(nt_status = - auth_get_sam_account(user_info->internal_username.str, + auth_get_sam_account(user_info->internal_username, &account))) { if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) nt_status = NT_STATUS_NOT_IMPLEMENTED; @@ -204,6 +202,9 @@ static NTSTATUS check_hostsequiv_security(const struct auth_context *auth_contex if (check_hosts_equiv(account)) { nt_status = make_server_info_sam(server_info, account); + if (!NT_STATUS_IS_OK(nt_status)) { + pdb_free_sam(&account); + } } else { pdb_free_sam(&account); nt_status = NT_STATUS_NOT_IMPLEMENTED; @@ -241,7 +242,7 @@ static NTSTATUS check_rhosts_security(const struct auth_context *auth_context, const char *home; if (!NT_STATUS_IS_OK(nt_status = - auth_get_sam_account(user_info->internal_username.str, + auth_get_sam_account(user_info->internal_username, &account))) { if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) nt_status = NT_STATUS_NOT_IMPLEMENTED; @@ -255,6 +256,9 @@ static NTSTATUS check_rhosts_security(const struct auth_context *auth_context, become_root(); if (check_user_equiv(pdb_get_username(account),client_name(),rhostsfile)) { nt_status = make_server_info_sam(server_info, account); + if (!NT_STATUS_IS_OK(nt_status)) { + pdb_free_sam(&account); + } } else { pdb_free_sam(&account); } diff --git a/source/auth/auth_sam.c b/source/auth/auth_sam.c index 558c181f704..fb53941b79f 100644 --- a/source/auth/auth_sam.c +++ b/source/auth/auth_sam.c @@ -62,8 +62,8 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context, &user_info->lm_resp, &user_info->nt_resp, &user_info->lm_interactive_pwd, &user_info->nt_interactive_pwd, username, - user_info->smb_name.str, - user_info->client_domain.str, + user_info->smb_name, + user_info->client_domain, lm_pw, nt_pw, user_sess_key, lm_sess_key); } @@ -177,22 +177,22 @@ static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx, fstring tok; const char *s = workstation_list; - const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name.str); + const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name); if (machine_name == NULL) return NT_STATUS_NO_MEMORY; while (next_token(&s, tok, ",", sizeof(tok))) { - DEBUG(10,("sam_account_ok: checking for workstation match %s and %s (len=%d)\n", - tok, user_info->wksta_name.str, user_info->wksta_name.len)); - if(strequal(tok, user_info->wksta_name.str)) { + DEBUG(10,("sam_account_ok: checking for workstation match %s and %s\n", + tok, user_info->wksta_name)); + if(strequal(tok, user_info->wksta_name)) { invalid_ws = False; break; } if (tok[0] == '+') { DEBUG(10,("sam_account_ok: checking for workstation %s in group: %s\n", machine_name, tok + 1)); - if (user_in_group_list(machine_name, tok + 1, NULL, 0)) { + if (user_in_group(machine_name, tok + 1)) { invalid_ws = False; break; } @@ -257,11 +257,12 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, /* get the account information */ become_root(); - ret = pdb_getsampwnam(sampass, user_info->internal_username.str); + ret = pdb_getsampwnam(sampass, user_info->internal_username); unbecome_root(); if (ret == False) { - DEBUG(3,("check_sam_security: Couldn't find user '%s' in passdb.\n", user_info->internal_username.str)); + DEBUG(3,("check_sam_security: Couldn't find user '%s' in " + "passdb.\n", user_info->internal_username)); pdb_free_sam(&sampass); return NT_STATUS_NO_SUCH_USER; } @@ -294,7 +295,7 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, } if (updated_autolock || updated_badpw){ become_root(); - if(!pdb_update_sam_account(sampass)) + if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass))) DEBUG(1, ("Failed to modify entry.\n")); unbecome_root(); } @@ -313,7 +314,7 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, if (updated_autolock || updated_badpw){ become_root(); - if(!pdb_update_sam_account(sampass)) + if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass))) DEBUG(1, ("Failed to modify entry.\n")); unbecome_root(); } @@ -329,13 +330,21 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, if (!NT_STATUS_IS_OK(nt_status = make_server_info_sam(server_info, sampass))) { DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status))); + pdb_free_sam(&sampass); data_blob_free(&user_sess_key); data_blob_free(&lm_sess_key); return nt_status; } - (*server_info)->user_session_key = user_sess_key; - (*server_info)->lm_session_key = lm_sess_key; + (*server_info)->user_session_key = + data_blob_talloc(*server_info, user_sess_key.data, + user_sess_key.length); + data_blob_free(&user_sess_key); + + (*server_info)->lm_session_key = + data_blob_talloc(*server_info, lm_sess_key.data, + lm_sess_key.length); + data_blob_free(&lm_sess_key); return nt_status; } @@ -369,8 +378,8 @@ static NTSTATUS check_samstrict_security(const struct auth_context *auth_context return NT_STATUS_LOGON_FAILURE; } - is_local_name = is_myname(user_info->domain.str); - is_my_domain = strequal(user_info->domain.str, lp_workgroup()); + is_local_name = is_myname(user_info->domain); + is_my_domain = strequal(user_info->domain, lp_workgroup()); /* check whether or not we service this domain/workgroup name */ @@ -379,7 +388,7 @@ static NTSTATUS check_samstrict_security(const struct auth_context *auth_context case ROLE_DOMAIN_MEMBER: if ( !is_local_name ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names (%s)\n", - user_info->domain.str, (lp_server_role() == ROLE_DOMAIN_MEMBER + user_info->domain, (lp_server_role() == ROLE_DOMAIN_MEMBER ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") )); return NT_STATUS_NOT_IMPLEMENTED; } @@ -387,7 +396,7 @@ static NTSTATUS check_samstrict_security(const struct auth_context *auth_context case ROLE_DOMAIN_BDC: if ( !is_local_name && !is_my_domain ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", - user_info->domain.str)); + user_info->domain)); return NT_STATUS_NOT_IMPLEMENTED; } default: /* name is ok */ diff --git a/source/auth/auth_script.c b/source/auth/auth_script.c index 1a715fca319..1bc33ec59e7 100644 --- a/source/auth/auth_script.c +++ b/source/auth/auth_script.c @@ -63,8 +63,8 @@ static NTSTATUS script_check_user_credentials(const struct auth_context *auth_co return NT_STATUS_INVALID_PARAMETER; } - secret_str_len = strlen(user_info->domain.str) + 1 + - strlen(user_info->smb_name.str) + 1 + + secret_str_len = strlen(user_info->domain) + 1 + + strlen(user_info->smb_name) + 1 + 16 + 1 + /* 8 bytes of challenge going to 16 */ 48 + 1 + /* 24 bytes of challenge going to 48 */ 48 + 1; @@ -74,9 +74,9 @@ static NTSTATUS script_check_user_credentials(const struct auth_context *auth_co return NT_STATUS_NO_MEMORY; } - safe_strcpy( secret_str, user_info->domain.str, secret_str_len - 1); + safe_strcpy( secret_str, user_info->domain, secret_str_len - 1); safe_strcat( secret_str, "\n", secret_str_len - 1); - safe_strcat( secret_str, user_info->smb_name.str, secret_str_len - 1); + safe_strcat( secret_str, user_info->smb_name, secret_str_len - 1); safe_strcat( secret_str, "\n", secret_str_len - 1); for (i = 0; i < 8; i++) { @@ -110,7 +110,7 @@ static NTSTATUS script_check_user_credentials(const struct auth_context *auth_co if (ret) { DEBUG(1,("script_check_user_credentials: failed to authenticate %s\\%s\n", - user_info->domain.str, user_info->smb_name.str )); + user_info->domain, user_info->smb_name )); /* auth failed. */ return NT_STATUS_NO_SUCH_USER; } diff --git a/source/auth/auth_server.c b/source/auth/auth_server.c index 7bce32ef2b2..8eed8bba6a4 100644 --- a/source/auth/auth_server.c +++ b/source/auth/auth_server.c @@ -235,7 +235,7 @@ static NTSTATUS check_smbserver_security(const struct auth_context *auth_context * password file. */ - if(is_myname(user_info->domain.str)) { + if(is_myname(user_info->domain)) { DEBUG(3,("check_smbserver_security: Requested domain was for this machine.\n")); return nt_status; } @@ -296,7 +296,7 @@ static NTSTATUS check_smbserver_security(const struct auth_context *auth_context if ((!tested_password_server) && (lp_paranoid_server_security())) { if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), - (char *)badpass, sizeof(badpass), user_info->domain.str)) { + (char *)badpass, sizeof(badpass), user_info->domain)) { /* * We connected to the password server so we @@ -342,11 +342,11 @@ use this machine as the password server.\n")); if (!user_info->encrypted) { /* Plaintext available */ - if (!cli_session_setup(cli, user_info->smb_name.str, + if (!cli_session_setup(cli, user_info->smb_name, (char *)user_info->plaintext_password.data, user_info->plaintext_password.length, NULL, 0, - user_info->domain.str)) { + user_info->domain)) { DEBUG(1,("password server %s rejected the password\n", cli->desthost)); /* Make this cli_nt_error() when the conversion is in */ nt_status = cli_nt_error(cli); @@ -354,12 +354,12 @@ use this machine as the password server.\n")); nt_status = NT_STATUS_OK; } } else { - if (!cli_session_setup(cli, user_info->smb_name.str, + if (!cli_session_setup(cli, user_info->smb_name, (char *)user_info->lm_resp.data, user_info->lm_resp.length, (char *)user_info->nt_resp.data, user_info->nt_resp.length, - user_info->domain.str)) { + user_info->domain)) { DEBUG(1,("password server %s rejected the password\n", cli->desthost)); /* Make this cli_nt_error() when the conversion is in */ nt_status = cli_nt_error(cli); @@ -380,11 +380,11 @@ use this machine as the password server.\n")); fstring real_username; struct passwd *pass; - if ( (pass = smb_getpwnam( user_info->internal_username.str, + if ( (pass = smb_getpwnam( NULL, user_info->internal_username, real_username, True )) != NULL ) { nt_status = make_server_info_pw(server_info, pass->pw_name, pass); - passwd_free(&pass); + talloc_free(pass); } else { diff --git a/source/auth/auth_unix.c b/source/auth/auth_unix.c index f744cba0c43..df0703d348b 100644 --- a/source/auth/auth_unix.c +++ b/source/auth/auth_unix.c @@ -62,7 +62,7 @@ static BOOL update_smbpassword_file(const char *user, const char *password) /* Now write it into the file. */ become_root(); - ret = pdb_update_sam_account (sampass); + ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass)); unbecome_root(); @@ -91,13 +91,13 @@ static NTSTATUS check_unix_security(const struct auth_context *auth_context, struct passwd *pass = NULL; become_root(); - pass = Get_Pwnam(user_info->internal_username.str); + pass = Get_Pwnam(user_info->internal_username); /** @todo This call assumes a ASCII password, no charset transformation is done. We may need to revisit this **/ nt_status = pass_check(pass, - pass ? pass->pw_name : user_info->internal_username.str, + pass ? pass->pw_name : user_info->internal_username, (char *)user_info->plaintext_password.data, user_info->plaintext_password.length-1, lp_update_encrypted() ? diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c index eb15fff7c8d..27dab9b9aa8 100644 --- a/source/auth/auth_util.c +++ b/source/auth/auth_util.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Bartlett 2001 Copyright (C) Jeremy Allison 2000-2001 Copyright (C) Rafal Szczesniak 2002 + Copyright (C) Volker Lendecke 2006 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 @@ -26,6 +27,12 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH +static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + const DOM_SID *group_sid, + BOOL is_guest, + int num_groupsids, + const DOM_SID *groupsids); /**************************************************************************** Create a UNIX user on demand. @@ -78,42 +85,32 @@ static NTSTATUS make_user_info(auth_usersupplied_info **user_info, DEBUG(5,("making strings for %s's user_info struct\n", internal_username)); - (*user_info)->smb_name.str = SMB_STRDUP(smb_name); - if ((*user_info)->smb_name.str) { - (*user_info)->smb_name.len = strlen(smb_name); - } else { + (*user_info)->smb_name = SMB_STRDUP(smb_name); + if ((*user_info)->smb_name == NULL) { free_user_info(user_info); return NT_STATUS_NO_MEMORY; } - (*user_info)->internal_username.str = SMB_STRDUP(internal_username); - if ((*user_info)->internal_username.str) { - (*user_info)->internal_username.len = strlen(internal_username); - } else { + (*user_info)->internal_username = SMB_STRDUP(internal_username); + if ((*user_info)->internal_username == NULL) { free_user_info(user_info); return NT_STATUS_NO_MEMORY; } - (*user_info)->domain.str = SMB_STRDUP(domain); - if ((*user_info)->domain.str) { - (*user_info)->domain.len = strlen(domain); - } else { + (*user_info)->domain = SMB_STRDUP(domain); + if ((*user_info)->domain == NULL) { free_user_info(user_info); return NT_STATUS_NO_MEMORY; } - (*user_info)->client_domain.str = SMB_STRDUP(client_domain); - if ((*user_info)->client_domain.str) { - (*user_info)->client_domain.len = strlen(client_domain); - } else { + (*user_info)->client_domain = SMB_STRDUP(client_domain); + if ((*user_info)->client_domain == NULL) { free_user_info(user_info); return NT_STATUS_NO_MEMORY; } - (*user_info)->wksta_name.str = SMB_STRDUP(wksta_name); - if ((*user_info)->wksta_name.str) { - (*user_info)->wksta_name.len = strlen(wksta_name); - } else { + (*user_info)->wksta_name = SMB_STRDUP(wksta_name); + if ((*user_info)->wksta_name == NULL) { free_user_info(user_info); return NT_STATUS_NO_MEMORY; } @@ -196,26 +193,28 @@ BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, const char *client_domain, const char *wksta_name, uint32 logon_parameters, - const uchar *lm_network_pwd, int lm_pwd_len, - const uchar *nt_network_pwd, int nt_pwd_len) + const uchar *lm_network_pwd, + int lm_pwd_len, + const uchar *nt_network_pwd, + int nt_pwd_len) { BOOL ret; - NTSTATUS nt_status; + NTSTATUS status; DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); - nt_status = make_user_info_map(user_info, - smb_name, client_domain, - wksta_name, - lm_pwd_len ? &lm_blob : NULL, - nt_pwd_len ? &nt_blob : NULL, - NULL, NULL, NULL, - True); + status = make_user_info_map(user_info, + smb_name, client_domain, + wksta_name, + lm_pwd_len ? &lm_blob : NULL, + nt_pwd_len ? &nt_blob : NULL, + NULL, NULL, NULL, + True); - if (NT_STATUS_IS_OK(nt_status)) { + if (NT_STATUS_IS_OK(status)) { (*user_info)->logon_parameters = logon_parameters; } - ret = NT_STATUS_IS_OK(nt_status) ? True : False; + ret = NT_STATUS_IS_OK(status) ? True : False; data_blob_free(&lm_blob); data_blob_free(&nt_blob); @@ -246,8 +245,11 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, ZERO_STRUCT(key); memcpy(key, dc_sess_key, 8); - if (lm_interactive_pwd) memcpy(lm_pwd, lm_interactive_pwd, sizeof(lm_pwd)); - if (nt_interactive_pwd) memcpy(nt_pwd, nt_interactive_pwd, sizeof(nt_pwd)); + if (lm_interactive_pwd) + memcpy(lm_pwd, lm_interactive_pwd, sizeof(lm_pwd)); + + if (nt_interactive_pwd) + memcpy(nt_pwd, nt_interactive_pwd, sizeof(nt_pwd)); #ifdef DEBUG_PASSWORD DEBUG(100,("key:")); @@ -275,10 +277,12 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, #endif if (lm_interactive_pwd) - SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response); + SMBOWFencrypt((const unsigned char *)lm_pwd, chal, + local_lm_response); if (nt_interactive_pwd) - SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response); + SMBOWFencrypt((const unsigned char *)nt_pwd, chal, + local_nt_response); /* Password info paranoia */ ZERO_STRUCT(key); @@ -293,26 +297,29 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, DATA_BLOB nt_interactive_blob; if (lm_interactive_pwd) { - local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); - lm_interactive_blob = data_blob(lm_pwd, sizeof(lm_pwd)); + local_lm_blob = data_blob(local_lm_response, + sizeof(local_lm_response)); + lm_interactive_blob = data_blob(lm_pwd, + sizeof(lm_pwd)); ZERO_STRUCT(lm_pwd); } if (nt_interactive_pwd) { - local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); - nt_interactive_blob = data_blob(nt_pwd, sizeof(nt_pwd)); + local_nt_blob = data_blob(local_nt_response, + sizeof(local_nt_response)); + nt_interactive_blob = data_blob(nt_pwd, + sizeof(nt_pwd)); ZERO_STRUCT(nt_pwd); } - nt_status = make_user_info_map(user_info, - smb_name, client_domain, - wksta_name, - lm_interactive_pwd ? &local_lm_blob : NULL, - nt_interactive_pwd ? &local_nt_blob : NULL, - lm_interactive_pwd ? &lm_interactive_blob : NULL, - nt_interactive_pwd ? &nt_interactive_blob : NULL, - NULL, - True); + nt_status = make_user_info_map( + user_info, + smb_name, client_domain, wksta_name, + lm_interactive_pwd ? &local_lm_blob : NULL, + nt_interactive_pwd ? &local_nt_blob : NULL, + lm_interactive_pwd ? &lm_interactive_blob : NULL, + nt_interactive_pwd ? &nt_interactive_blob : NULL, + NULL, True); if (NT_STATUS_IS_OK(nt_status)) { (*user_info)->logon_parameters = logon_parameters; @@ -347,17 +354,21 @@ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, * Not encrypted - do so. */ - DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted format.\n")); + DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted " + "format.\n")); if (plaintext_password.data) { unsigned char local_lm_response[24]; #ifdef DEBUG_PASSWORD - DEBUG(10,("Unencrypted password (len %d):\n",(int)plaintext_password.length)); - dump_data(100, (const char *)plaintext_password.data, plaintext_password.length); + DEBUG(10,("Unencrypted password (len %d):\n", + (int)plaintext_password.length)); + dump_data(100, (const char *)plaintext_password.data, + plaintext_password.length); #endif - SMBencrypt( (const char *)plaintext_password.data, (const uchar*)chal, local_lm_response); + SMBencrypt( (const char *)plaintext_password.data, + (const uchar*)chal, local_lm_response); local_lm_blob = data_blob(local_lm_response, 24); /* We can't do an NT hash here, as the password needs to be @@ -369,14 +380,14 @@ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, local_nt_blob = data_blob(NULL, 0); } - ret = make_user_info_map(user_info, smb_name, - client_domain, - get_remote_machine_name(), - local_lm_blob.data ? &local_lm_blob : NULL, - local_nt_blob.data ? &local_nt_blob : NULL, - NULL, NULL, - plaintext_password.data ? &plaintext_password : NULL, - False); + ret = make_user_info_map( + user_info, smb_name, client_domain, + get_remote_machine_name(), + local_lm_blob.data ? &local_lm_blob : NULL, + local_nt_blob.data ? &local_nt_blob : NULL, + NULL, NULL, + plaintext_password.data ? &plaintext_password : NULL, + False); data_blob_free(&local_lm_blob); return NT_STATUS_IS_OK(ret) ? True : False; @@ -426,7 +437,6 @@ BOOL make_user_info_guest(auth_usersupplied_info **user_info) void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token) { - fstring sid_str; size_t i; if (!token) { @@ -434,12 +444,15 @@ void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token) return; } - DEBUGC(dbg_class, dbg_lev, ("NT user token of user %s\n", - sid_to_string(sid_str, &token->user_sids[0]) )); - DEBUGADDC(dbg_class, dbg_lev, ("contains %lu SIDs\n", (unsigned long)token->num_sids)); + DEBUGC(dbg_class, dbg_lev, + ("NT user token of user %s\n", + sid_string_static(&token->user_sids[0]) )); + DEBUGADDC(dbg_class, dbg_lev, + ("contains %lu SIDs\n", (unsigned long)token->num_sids)); for (i = 0; i < token->num_sids; i++) - DEBUGADDC(dbg_class, dbg_lev, ("SID[%3lu]: %s\n", (unsigned long)i, - sid_to_string(sid_str, &token->user_sids[i]))); + DEBUGADDC(dbg_class, dbg_lev, + ("SID[%3lu]: %s\n", (unsigned long)i, + sid_string_static(&token->user_sids[i]))); dump_se_priv( dbg_class, dbg_lev, &token->privileges ); } @@ -448,464 +461,568 @@ void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token) prints a UNIX 'token' to debug output. ****************************************************************************/ -void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, int n_groups, gid_t *groups) +void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, + int n_groups, gid_t *groups) { int i; - DEBUGC(dbg_class, dbg_lev, ("UNIX token of user %ld\n", (long int)uid)); + DEBUGC(dbg_class, dbg_lev, + ("UNIX token of user %ld\n", (long int)uid)); - DEBUGADDC(dbg_class, dbg_lev, ("Primary group is %ld and contains %i supplementary groups\n", (long int)gid, n_groups)); + DEBUGADDC(dbg_class, dbg_lev, + ("Primary group is %ld and contains %i supplementary " + "groups\n", (long int)gid, n_groups)); for (i = 0; i < n_groups; i++) DEBUGADDC(dbg_class, dbg_lev, ("Group[%3i]: %ld\n", i, (long int)groups[i])); } -/**************************************************************************** - Create the SID list for this user. -****************************************************************************/ +/****************************************************************************** + Create a token for the root user to be used internally by smbd. + This is similar to running under the context of the LOCAL_SYSTEM account + in Windows. This is a read-only token. Do not modify it or free() it. + Create a copy if your need to change it. +******************************************************************************/ -static NTSTATUS create_nt_user_token(const DOM_SID *user_sid, const DOM_SID *group_sid, - int n_groupSIDs, DOM_SID *groupSIDs, - BOOL is_guest, NT_USER_TOKEN **token) +NT_USER_TOKEN *get_root_nt_token( void ) { - NTSTATUS nt_status = NT_STATUS_OK; - NT_USER_TOKEN *ptoken; - int i; - int sid_ndx; - DOM_SID domadm; - BOOL is_domain_admin = False; - BOOL domain_mode = False; + static NT_USER_TOKEN *token = NULL; + DOM_SID u_sid, g_sid; + struct passwd *pw; - if ((ptoken = SMB_MALLOC_P(NT_USER_TOKEN)) == NULL) { - DEBUG(0, ("create_nt_user_token: Out of memory allocating token\n")); - nt_status = NT_STATUS_NO_MEMORY; - return nt_status; + if ( token ) + return token; + + if ( !(pw = getpwnam( "root" )) ) { + DEBUG(0,("get_root_nt_token: getpwnam\"root\") failed!\n")); + return NULL; } + + /* get the user and primary group SIDs; although the + BUILTIN\Administrators SId is really the one that matters here */ + + uid_to_sid(&u_sid, pw->pw_uid); + gid_to_sid(&g_sid, pw->pw_gid); - ZERO_STRUCTP(ptoken); + token = create_local_nt_token(NULL, &u_sid, &g_sid, False, + 1, &global_sid_Builtin_Administrators); + return token; +} - ptoken->num_sids = n_groupSIDs + 5; +static int server_info_dtor(void *p) +{ + auth_serversupplied_info *server_info = + talloc_get_type_abort(p, auth_serversupplied_info); - if ((ptoken->user_sids = SMB_MALLOC_ARRAY( DOM_SID, ptoken->num_sids )) == NULL) { - DEBUG(0, ("create_nt_user_token: Out of memory allocating SIDs\n")); - nt_status = NT_STATUS_NO_MEMORY; - return nt_status; + if (server_info->sam_account != NULL) { + pdb_free_sam(&server_info->sam_account); } - - memset((char*)ptoken->user_sids,0,sizeof(DOM_SID) * ptoken->num_sids); - - /* - * Note - user SID *MUST* be first in token ! - * se_access_check depends on this. - * - * Primary group SID is second in token. Convention. - */ - sid_copy(&ptoken->user_sids[PRIMARY_USER_SID_INDEX], user_sid); - if (group_sid) - sid_copy(&ptoken->user_sids[PRIMARY_GROUP_SID_INDEX], group_sid); + ZERO_STRUCTP(server_info); + return 0; +} - /* - * Finally add the "standard" SIDs. - * The only difference between guest and "anonymous" (which we - * don't really support) is the addition of Authenticated_Users. - */ +/*************************************************************************** + Make a server_info struct. Free with talloc_free(). +***************************************************************************/ + +static auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx) +{ + struct auth_serversupplied_info *result; - sid_copy(&ptoken->user_sids[2], &global_sid_World); - sid_copy(&ptoken->user_sids[3], &global_sid_Network); + result = TALLOC_ZERO_P(mem_ctx, auth_serversupplied_info); + if (result == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } - if (is_guest) - sid_copy(&ptoken->user_sids[4], &global_sid_Builtin_Guests); - else - sid_copy(&ptoken->user_sids[4], &global_sid_Authenticated_Users); - - sid_ndx = 5; /* next available spot */ - - /* this is where we construct the domain admins SID if we can - so that we can add the BUILTIN\Administrators SID to the token */ - - ZERO_STRUCT( domadm ); - if ( IS_DC || lp_server_role()==ROLE_DOMAIN_MEMBER ) { - domain_mode = True; - - if ( IS_DC ) - sid_copy( &domadm, get_global_sam_sid() ); - else { - /* if we a re a member server and cannot find - out domain SID then reset the domain_mode flag */ - if ( !secrets_fetch_domain_sid( lp_workgroup(), &domadm ) ) - domain_mode = False; - } + talloc_set_destructor(result, server_info_dtor); + + /* Initialise the uid and gid values to something non-zero + which may save us from giving away root access if there + is a bug in allocating these fields. */ + + result->uid = -1; + result->gid = -1; + return result; +} - sid_append_rid( &domadm, DOMAIN_GROUP_RID_ADMINS ); +/*************************************************************************** + Make (and fill) a user_info struct from a SAM_ACCOUNT +***************************************************************************/ + +NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info, + SAM_ACCOUNT *sampass) +{ + NTSTATUS status; + struct passwd *pwd; + gid_t *gids; + auth_serversupplied_info *result; + + pwd = getpwnam_alloc(NULL, pdb_get_username(sampass)); + if ( pwd == NULL ) { + DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n", + pdb_get_username(sampass))); + return NT_STATUS_NO_SUCH_USER; } - - /* add the group SIDs to teh token */ - - for (i = 0; i < n_groupSIDs; i++) { - size_t check_sid_idx; - for (check_sid_idx = 1; check_sid_idx < ptoken->num_sids; check_sid_idx++) { - if (sid_equal(&ptoken->user_sids[check_sid_idx], - &groupSIDs[i])) { - break; - } - } - - if (check_sid_idx >= ptoken->num_sids) /* Not found already */ { - sid_copy(&ptoken->user_sids[sid_ndx++], &groupSIDs[i]); - } else { - ptoken->num_sids--; - } - - /* here we check if the user is a domain admin and add the - BUILTIN\Administrators SID to the token the group membership - check succeeds. */ - if ( domain_mode ) { - if ( sid_equal( &domadm, &groupSIDs[i] ) ) - is_domain_admin = True; - } - + result = make_server_info(NULL); + if (result == NULL) { + talloc_free(pwd); + return NT_STATUS_NO_MEMORY; } - /* finally realloc the SID array and add the BUILTIN\Administrators - SID if necessary */ + result->sam_account = sampass; + result->unix_name = talloc_strdup(result, pwd->pw_name); + result->gid = pwd->pw_gid; + result->uid = pwd->pw_uid; + + talloc_free(pwd); - if ( is_domain_admin ) { - DOM_SID *sids; + status = pdb_enum_group_memberships(result, sampass, + &result->sids, &gids, + &result->num_sids); - if ( !(sids = SMB_REALLOC_ARRAY( ptoken->user_sids, DOM_SID, ptoken->num_sids+1 )) ) - DEBUG(0,("create_nt_user_token: Failed to realloc SID arry of size %d\n", ptoken->num_sids+1)); - else { - ptoken->user_sids = sids; - sid_copy( &(ptoken->user_sids)[ptoken->num_sids++], &global_sid_Builtin_Administrators ); - } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_enum_group_memberships failed: %s\n", + nt_errstr(status))); + result->sam_account = NULL; /* Don't free on error exit. */ + talloc_free(result); + return status; } - /* add privileges assigned to this user */ + /* For now we throw away the gids and convert via sid_to_gid + * later. This needs fixing, but I'd like to get the code straight and + * simple first. */ + talloc_free(gids); - get_privileges_for_sids( &ptoken->privileges, ptoken->user_sids, ptoken->num_sids ); - - debug_nt_user_token(DBGC_AUTH, 10, ptoken); - - if ((lp_log_nt_token_command() != NULL) && - (strlen(lp_log_nt_token_command()) > 0)) { - TALLOC_CTX *mem_ctx; - char *command; - char *group_sidstr; - - mem_ctx = talloc_init("setnttoken"); - if (mem_ctx == NULL) - return NT_STATUS_NO_MEMORY; + DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n", + pdb_get_username(sampass), result->unix_name)); - group_sidstr = talloc_strdup(mem_ctx, ""); - for (i=1; inum_sids; i++) { - group_sidstr = talloc_asprintf( - mem_ctx, "%s %s", group_sidstr, - sid_string_static(&ptoken->user_sids[i])); - } + *server_info = result; - command = talloc_string_sub( - mem_ctx, lp_log_nt_token_command(), - "%s", sid_string_static(&ptoken->user_sids[0])); - command = talloc_string_sub( - mem_ctx, command, "%t", group_sidstr); + return NT_STATUS_OK; +} + +/* + * Add alias SIDs from memberships within the partially created token SID list + */ - if (command == NULL) { - talloc_destroy(mem_ctx); +static NTSTATUS add_aliases(TALLOC_CTX *tmp_ctx, const DOM_SID *domain_sid, + struct nt_user_token *token) +{ + uint32 *aliases; + size_t i, num_aliases; + NTSTATUS status; + + aliases = NULL; + num_aliases = 0; + + status = pdb_enum_alias_memberships(tmp_ctx, domain_sid, + token->user_sids, + token->num_sids, + &aliases, &num_aliases); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_enum_alias_memberships failed: %s\n", + nt_errstr(status))); + return status; + } + + for (i=0; iuser_sids, + &token->num_sids); + if (token->user_sids == NULL) { + DEBUG(0, ("add_sid_to_array failed\n")); return NT_STATUS_NO_MEMORY; } + } - DEBUG(8, ("running command: [%s]\n", command)); - if (smbrun(command, NULL) != 0) { - DEBUG(0, ("Could not log NT token\n")); - nt_status = NT_STATUS_ACCESS_DENIED; - } - talloc_destroy(mem_ctx); + return NT_STATUS_OK; +} + +static NTSTATUS log_nt_token(TALLOC_CTX *tmp_ctx, NT_USER_TOKEN *token) +{ + char *command; + char *group_sidstr; + size_t i; + + if ((lp_log_nt_token_command() == NULL) || + (strlen(lp_log_nt_token_command()) == 0)) { + return NT_STATUS_OK; } - *token = ptoken; + group_sidstr = talloc_strdup(tmp_ctx, ""); + for (i=1; inum_sids; i++) { + group_sidstr = talloc_asprintf( + tmp_ctx, "%s %s", group_sidstr, + sid_string_static(&token->user_sids[i])); + } - return nt_status; -} + command = talloc_string_sub( + tmp_ctx, lp_log_nt_token_command(), + "%s", sid_string_static(&token->user_sids[0])); + command = talloc_string_sub(tmp_ctx, command, "%t", group_sidstr); -/**************************************************************************** - Create the SID list for this user. -****************************************************************************/ + if (command == NULL) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(8, ("running command: [%s]\n", command)); + if (smbrun(command, NULL) != 0) { + DEBUG(0, ("Could not log NT token\n")); + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} -NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest) +/* + * Create a NT token for the user, expanding local aliases + */ + +static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + const DOM_SID *group_sid, + BOOL is_guest, + int num_groupsids, + const DOM_SID *groupsids) { - DOM_SID user_sid; - DOM_SID group_sid; - DOM_SID *group_sids; - NT_USER_TOKEN *token; + TALLOC_CTX *tmp_ctx; + struct nt_user_token *result = NULL; int i; + NTSTATUS status; - if (!NT_STATUS_IS_OK(uid_to_sid(&user_sid, uid))) { + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); return NULL; } - if (!NT_STATUS_IS_OK(gid_to_sid(&group_sid, gid))) { - return NULL; + + result = TALLOC_ZERO_P(tmp_ctx, NT_USER_TOKEN); + if (result == NULL) { + DEBUG(0, ("talloc failed\n")); + goto done; } - group_sids = SMB_MALLOC_ARRAY(DOM_SID, ngroups); - if (!group_sids) { - DEBUG(0, ("create_nt_token: malloc() failed for DOM_SID list!\n")); - return NULL; + /* First create the default SIDs */ + + add_sid_to_array(result, user_sid, + &result->user_sids, &result->num_sids); + add_sid_to_array(result, group_sid, + &result->user_sids, &result->num_sids); + add_sid_to_array(result, &global_sid_World, + &result->user_sids, &result->num_sids); + add_sid_to_array(result, &global_sid_Network, + &result->user_sids, &result->num_sids); + + if (is_guest) { + add_sid_to_array(result, &global_sid_Builtin_Guests, + &result->user_sids, &result->num_sids); + } else { + add_sid_to_array(result, &global_sid_Authenticated_Users, + &result->user_sids, &result->num_sids); } - /* convert the Unix group ids to SIDS */ + /* Now the SIDs we got from authentication. These are the ones from + * the info3 struct or from the pdb_enum_group_memberships, depending + * on who authenticated the user. */ - for (i = 0; i < ngroups; i++) { - if (!NT_STATUS_IS_OK(gid_to_sid(&(group_sids)[i], (groups)[i]))) { - DEBUG(1, ("create_nt_token: failed to convert gid %ld to a sid!\n", (long int)groups[i])); - SAFE_FREE(group_sids); - return NULL; - } + for (i=0; iuser_sids, &result->num_sids); } - if (!NT_STATUS_IS_OK(create_nt_user_token(&user_sid, &group_sid, - ngroups, group_sids, is_guest, &token))) { - SAFE_FREE(group_sids); - return NULL; + if (lp_winbind_nested_groups()) { + + /* Now add the aliases. First the one from our local SAM */ + + status = add_aliases(tmp_ctx, get_global_sam_sid(), result); + + if (!NT_STATUS_IS_OK(status)) { + result = NULL; + goto done; + } + + /* Finally the builtin ones */ + + status = add_aliases(tmp_ctx, &global_sid_Builtin, result); + + if (!NT_STATUS_IS_OK(status)) { + result = NULL; + goto done; + } + } else { + + /* Play jerry's trick to auto-add local admins if we're a + * domain admin. */ + + DOM_SID dom_admins; + BOOL domain_mode = False; + + if (IS_DC) { + sid_compose(&dom_admins, get_global_sam_sid(), + DOMAIN_GROUP_RID_ADMINS); + domain_mode = True; + } + if ((lp_server_role() == ROLE_DOMAIN_MEMBER) && + (secrets_fetch_domain_sid(lp_workgroup(), &dom_admins))) { + sid_append_rid(&dom_admins, DOMAIN_GROUP_RID_ADMINS); + domain_mode = True; + } + + if (domain_mode) { + for (i=0; inum_sids; i++) { + if (sid_equal(&dom_admins, + &result->user_sids[i])) { + add_sid_to_array_unique( + result, + &global_sid_Builtin_Administrators, + &result->user_sids, + &result->num_sids); + break; + } + } + + } } - SAFE_FREE(group_sids); + get_privileges_for_sids(&result->privileges, result->user_sids, + result->num_sids); - return token; + talloc_steal(mem_ctx, result); + + done: + talloc_free(tmp_ctx); + return result; } -/****************************************************************************** - Create a token for the root user to be used internally by smbd. - This is similar to running under the context of the LOCAL_SYSTEM account - in Windows. This is a read-only token. Do not modify it or free() it. - Create a copy if your need to change it. -******************************************************************************/ +/* + * Create the token to use from server_info->sam_account and + * server_info->sids (the info3/sam groups). Find the unix gids. + */ -NT_USER_TOKEN *get_root_nt_token( void ) +NTSTATUS create_local_token(auth_serversupplied_info *server_info) { - static NT_USER_TOKEN *token = NULL; - DOM_SID u_sid, g_sid; - DOM_SID g_sids[1]; - struct passwd *pw; - NTSTATUS result; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + size_t i; - if ( token ) - return token; - - if ( !(pw = getpwnam( "root" )) ) { - DEBUG(0,("get_root_nt_token: getpwnam\"root\") failed!\n")); - return NULL; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } + + server_info->ptok = create_local_nt_token( + server_info, + pdb_get_user_sid(server_info->sam_account), + pdb_get_group_sid(server_info->sam_account), + server_info->guest, + server_info->num_sids, server_info->sids); - /* get the user and primary group SIDs; although the - BUILTIN\Administrators SId is really the one that matters here */ - - if ( !NT_STATUS_IS_OK(uid_to_sid(&u_sid, pw->pw_uid)) ) - return NULL; - if ( !NT_STATUS_IS_OK(gid_to_sid(&g_sid, pw->pw_gid)) ) - return NULL; - - sid_copy( &g_sids[0], &global_sid_Builtin_Administrators ); - - result = create_nt_user_token( &u_sid, &g_sid, 1, g_sids, False, &token); + /* Convert the SIDs to gids. */ + + server_info->n_groups = 0; + server_info->groups = NULL; + + /* Start at index 1, where the groups start. */ + + for (i=1; iptok->num_sids; i++) { + gid_t gid; + DOM_SID *sid = &server_info->ptok->user_sids[i]; + + if (!sid_to_gid(sid, &gid)) { + DEBUG(10, ("Could not convert SID %s to gid, " + "ignoring it\n", sid_string_static(sid))); + continue; + } + add_gid_to_array_unique(server_info, gid, &server_info->groups, + &server_info->n_groups); + } - return NT_STATUS_IS_OK(result) ? token : NULL; + debug_nt_user_token(DBGC_AUTH, 10, server_info->ptok); + + status = log_nt_token(mem_ctx, server_info->ptok); + + talloc_free(mem_ctx); + return status; } -/****************************************************************************** - * this function returns the groups (SIDs) of the local SAM the user is in. - * If this samba server is a DC of the domain the user belongs to, it returns - * both domain groups and local / builtin groups. If the user is in a trusted - * domain, or samba is a member server of a domain, then this function returns - * local and builtin groups the user is a member of. +/* + * Create an artificial NT token given just a username. (Initially indended + * for force user) * - * currently this is a hack, as there is no sam implementation that is capable - * of groups. + * We go through lookup_name() to avoid problems we had with 'winbind use + * default domain'. * - * NOTE!! This function will fail if you pass in a winbind user without - * the domain --jerry - ******************************************************************************/ - -static NTSTATUS get_user_groups(const char *username, uid_t uid, gid_t gid, - size_t *n_groups, DOM_SID **groups, gid_t **unix_groups) + * We have 3 cases: + * + * unmapped unix users: Go directly to nss to find the user's group. + * + * A passdb user: The list of groups is provided by pdb_enum_group_memberships. + * + * If the user is provided by winbind, the primary gid is set to "domain + * users" of the user's domain. For an explanation why this is necessary, see + * the thread starting at + * http://lists.samba.org/archive/samba-technical/2006-January/044803.html. + */ + +NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username, + BOOL is_guest, + uid_t *uid, gid_t *gid, + char **found_username, + struct nt_user_token **token) { - int n_unix_groups; - int i; + NTSTATUS result = NT_STATUS_NO_SUCH_USER; + TALLOC_CTX *tmp_ctx; + DOM_SID user_sid; + enum SID_NAME_USE type; + gid_t *gids; + DOM_SID primary_group_sid; + DOM_SID *group_sids; + size_t num_group_sids; - *n_groups = 0; - *groups = NULL; + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } - if (strchr(username, *lp_winbind_separator()) == NULL) { - NTSTATUS result; + if (!lookup_name(tmp_ctx, username, LOOKUP_NAME_ALL, + NULL, NULL, &user_sid, &type)) { + DEBUG(1, ("lookup_name for %s failed\n", username)); + goto done; + } - become_root(); - result = pdb_enum_group_memberships(username, gid, groups, - unix_groups, n_groups); - unbecome_root(); - return result; + if (type != SID_NAME_USER) { + DEBUG(1, ("%s is a %s, not a user\n", username, + sid_type_lookup(type))); + goto done; } - /* We have the separator, this must be winbind */ - - n_unix_groups = winbind_getgroups( username, unix_groups ); + if (!sid_to_uid(&user_sid, uid)) { + DEBUG(1, ("sid_to_uid for %s (%s) failed\n", + username, sid_string_static(&user_sid))); + goto done; + } - DEBUG(10,("get_user_groups: winbind_getgroups(%s): result = %s\n", - username, n_unix_groups == -1 ? "FAIL" : "SUCCESS")); - - if ( n_unix_groups == -1 ) - return NT_STATUS_NO_SUCH_USER; /* what should this return - * value be? */ + if (sid_check_is_in_unix_users(&user_sid)) { - debug_unix_user_token(DBGC_CLASS, 5, uid, gid, n_unix_groups, *unix_groups); - - /* now setup the space for storing the SIDS */ - - if (n_unix_groups > 0) { - - *groups = SMB_MALLOC_ARRAY(DOM_SID, n_unix_groups); - - if (!*groups) { - DEBUG(0, ("get_user_group: malloc() failed for DOM_SID list!\n")); - SAFE_FREE(*unix_groups); - return NT_STATUS_NO_MEMORY; + /* This is a unix user not in passdb. We need to ask nss + * directly, without consulting passdb */ + + struct passwd *pass; + size_t i; + + pass = getpwuid_alloc(tmp_ctx, *uid); + if (pass == NULL) { + DEBUG(1, ("getpwuid(%d) for user %s failed\n", + *uid, username)); + goto done; } - } - *n_groups = n_unix_groups; + *gid = pass->pw_gid; + gid_to_sid(&primary_group_sid, pass->pw_gid); - for (i = 0; i < *n_groups; i++) { - if (!NT_STATUS_IS_OK(gid_to_sid(&(*groups)[i], (*unix_groups)[i]))) { - DEBUG(1, ("get_user_groups: failed to convert gid %ld to a sid!\n", - (long int)(*unix_groups)[i+1])); - SAFE_FREE(*groups); - SAFE_FREE(*unix_groups); - return NT_STATUS_NO_SUCH_USER; + if (!getgroups_unix_user(tmp_ctx, username, pass->pw_gid, + &gids, &num_group_sids)) { + DEBUG(1, ("getgroups_unix_user for user %s failed\n", + username)); + goto done; } - } - - return NT_STATUS_OK; -} -/*************************************************************************** - Make a user_info struct -***************************************************************************/ + group_sids = talloc_array(tmp_ctx, DOM_SID, num_group_sids); + if (group_sids == NULL) { + DEBUG(1, ("talloc_array failed\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } -static NTSTATUS make_server_info(auth_serversupplied_info **server_info) -{ - *server_info = SMB_MALLOC_P(auth_serversupplied_info); - if (!*server_info) { - DEBUG(0,("make_server_info: malloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*server_info); + for (i=0; ipw_name); - /* Initialise the uid and gid values to something non-zero - which may save us from giving away root access if there - is a bug in allocating these fields. */ + } else if (sid_check_is_in_our_domain(&user_sid)) { - (*server_info)->uid = -1; - (*server_info)->gid = -1; + /* This is a passdb user, so ask passdb */ - return NT_STATUS_OK; -} + SAM_ACCOUNT *sam_acct = NULL; -/*************************************************************************** -Fill a server_info struct from a SAM_ACCOUNT with their groups -***************************************************************************/ + result = pdb_init_sam_talloc(tmp_ctx, &sam_acct); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } -static NTSTATUS add_user_groups(auth_serversupplied_info **server_info, - const char * unix_username, - SAM_ACCOUNT *sampass, - uid_t uid, gid_t gid) -{ - NTSTATUS nt_status; - const DOM_SID *user_sid = pdb_get_user_sid(sampass); - const DOM_SID *group_sid = pdb_get_group_sid(sampass); - size_t n_groupSIDs = 0; - DOM_SID *groupSIDs = NULL; - gid_t *unix_groups = NULL; - NT_USER_TOKEN *token; - BOOL is_guest; - uint32 rid; + if (!pdb_getsampwsid(sam_acct, &user_sid)) { + DEBUG(1, ("pdb_getsampwsid(%s) for user %s failed\n", + sid_string_static(&user_sid), username)); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } - nt_status = get_user_groups(unix_username, uid, gid, - &n_groupSIDs, &groupSIDs, &unix_groups); - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(4,("get_user_groups_from_local_sam failed\n")); - free_server_info(server_info); - return nt_status; - } - - is_guest = (sid_peek_rid(user_sid, &rid) && rid == DOMAIN_USER_RID_GUEST); + sid_copy(&primary_group_sid, pdb_get_group_sid(sam_acct)); - if (!NT_STATUS_IS_OK(nt_status = create_nt_user_token(user_sid, group_sid, - n_groupSIDs, groupSIDs, is_guest, - &token))) - { - DEBUG(4,("create_nt_user_token failed\n")); - SAFE_FREE(groupSIDs); - SAFE_FREE(unix_groups); - free_server_info(server_info); - return nt_status; - } - - SAFE_FREE(groupSIDs); + result = pdb_enum_group_memberships(tmp_ctx, sam_acct, + &group_sids, &gids, + &num_group_sids); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("enum_group_memberships failed for %s\n", + username)); + goto done; + } - (*server_info)->n_groups = n_groupSIDs; - (*server_info)->groups = unix_groups; - (*server_info)->ptok = token; + *found_username = talloc_strdup(mem_ctx, + pdb_get_username(sam_acct)); - return nt_status; -} + } else { -/*************************************************************************** - Make (and fill) a user_info struct from a SAM_ACCOUNT -***************************************************************************/ + /* This user is from winbind, force the primary gid to the + * user's "domain users" group. Under certain circumstances + * (user comes from NT4), this might be a loss of + * information. But we can not rely on winbind getting the + * correct info. AD might prohibit winbind looking up that + * information. */ -NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info, - SAM_ACCOUNT *sampass) -{ - NTSTATUS nt_status; - struct passwd *pwd; + uint32 dummy; - if (!NT_STATUS_IS_OK(nt_status = make_server_info(server_info))) - return nt_status; + sid_copy(&primary_group_sid, &user_sid); + sid_split_rid(&primary_group_sid, &dummy); + sid_append_rid(&primary_group_sid, DOMAIN_GROUP_RID_USERS); - (*server_info)->sam_account = sampass; + if (!sid_to_gid(&primary_group_sid, gid)) { + DEBUG(1, ("sid_to_gid(%s) failed\n", + sid_string_static(&primary_group_sid))); + goto done; + } - if ( !(pwd = getpwnam_alloc(pdb_get_username(sampass))) ) { - DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n", - pdb_get_username(sampass))); - free_server_info(server_info); - return NT_STATUS_NO_SUCH_USER; - } - (*server_info)->unix_name = smb_xstrdup(pwd->pw_name); - (*server_info)->gid = pwd->pw_gid; - (*server_info)->uid = pwd->pw_uid; - - passwd_free(&pwd); + num_group_sids = 0; + group_sids = NULL; - if (!NT_STATUS_IS_OK(nt_status = add_user_groups(server_info, pdb_get_username(sampass), - sampass, - (*server_info)->uid, - (*server_info)->gid))) - { - free_server_info(server_info); - return nt_status; + *found_username = talloc_strdup(mem_ctx, username); } - (*server_info)->sam_fill_level = SAM_FILL_ALL; - DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n", - pdb_get_username(sampass), - (*server_info)->unix_name)); + *token = create_local_nt_token(mem_ctx, &user_sid, &primary_group_sid, + is_guest, num_group_sids, group_sids); - return nt_status; + if ((*token == NULL) || (*found_username == NULL)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + result = NT_STATUS_OK; + done: + talloc_free(tmp_ctx); + return result; } /*************************************************************************** - Make (and fill) a user_info struct from a Kerberos PAC logon_info by conversion - to a SAM_ACCOUNT + Make (and fill) a user_info struct from a Kerberos PAC logon_info by + conversion to a SAM_ACCOUNT ***************************************************************************/ NTSTATUS make_server_info_pac(auth_serversupplied_info **server_info, @@ -913,16 +1030,22 @@ NTSTATUS make_server_info_pac(auth_serversupplied_info **server_info, struct passwd *pwd, PAC_LOGON_INFO *logon_info) { - NTSTATUS nt_status; + NTSTATUS status; SAM_ACCOUNT *sampass = NULL; DOM_SID user_sid, group_sid; fstring dom_name; + auth_serversupplied_info *result; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(&sampass, pwd))) { - return nt_status; + status = pdb_init_sam_pw(&sampass, pwd); + + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (!NT_STATUS_IS_OK(nt_status = make_server_info(server_info))) { - return nt_status; + + result = make_server_info(NULL); + if (result == NULL) { + pdb_free_sam(&sampass); + return NT_STATUS_NO_MEMORY; } /* only copy user_sid, group_sid and domain name out of the PAC for @@ -941,20 +1064,18 @@ NTSTATUS make_server_info_pac(auth_serversupplied_info **server_info, pdb_set_logon_count(sampass, logon_info->info3.logon_count, PDB_SET); - (*server_info)->sam_account = sampass; + result->sam_account = sampass; + result->unix_name = talloc_strdup(result, unix_username); + result->uid = pwd->pw_uid; + result->gid = pwd->pw_gid; - if (!NT_STATUS_IS_OK(nt_status = add_user_groups(server_info, unix_username, - sampass, pwd->pw_uid, pwd->pw_gid))) - { - return nt_status; - } + /* TODO: Add groups from pac */ + result->sids = NULL; + result->num_sids = 0; - (*server_info)->unix_name = smb_xstrdup(unix_username); + *server_info = result; - (*server_info)->sam_fill_level = SAM_FILL_ALL; - (*server_info)->uid = pwd->pw_uid; - (*server_info)->gid = pwd->pw_gid; - return nt_status; + return NT_STATUS_OK; } @@ -967,93 +1088,172 @@ NTSTATUS make_server_info_pw(auth_serversupplied_info **server_info, char *unix_username, struct passwd *pwd) { - NTSTATUS nt_status; + NTSTATUS status; SAM_ACCOUNT *sampass = NULL; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(&sampass, pwd))) { - return nt_status; + gid_t *gids; + auth_serversupplied_info *result; + + status = pdb_init_sam_pw(&sampass, pwd); + + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (!NT_STATUS_IS_OK(nt_status = make_server_info(server_info))) { - return nt_status; + + result = make_server_info(NULL); + + if (!NT_STATUS_IS_OK(status)) { + pdb_free_sam(&sampass); + return status; } - (*server_info)->sam_account = sampass; + result->sam_account = sampass; + result->unix_name = talloc_strdup(result, unix_username); + result->uid = pwd->pw_uid; + result->gid = pwd->pw_gid; - if (!NT_STATUS_IS_OK(nt_status = add_user_groups(server_info, unix_username, - sampass, pwd->pw_uid, pwd->pw_gid))) - { - return nt_status; + status = pdb_enum_group_memberships(result, sampass, + &result->sids, &gids, + &result->num_sids); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_enum_group_memberships failed: %s\n", + nt_errstr(status))); + talloc_free(result); + return status; } - (*server_info)->unix_name = smb_xstrdup(unix_username); + /* For now we throw away the gids and convert via sid_to_gid + * later. This needs fixing, but I'd like to get the code straight and + * simple first. */ + talloc_free(gids); - (*server_info)->sam_fill_level = SAM_FILL_ALL; - (*server_info)->uid = pwd->pw_uid; - (*server_info)->gid = pwd->pw_gid; - return nt_status; + *server_info = result; + + return NT_STATUS_OK; } /*************************************************************************** Make (and fill) a user_info struct for a guest login. + This *must* succeed for smbd to start. If there is no mapping entry for + the guest gid, then create one. ***************************************************************************/ static NTSTATUS make_new_server_info_guest(auth_serversupplied_info **server_info) { - NTSTATUS nt_status; + NTSTATUS status; SAM_ACCOUNT *sampass = NULL; DOM_SID guest_sid; + BOOL ret; + static const char zeros[16]; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) { - return nt_status; + status = pdb_init_sam(&sampass); + + if (!NT_STATUS_IS_OK(status)) { + return status; } sid_copy(&guest_sid, get_global_sam_sid()); sid_append_rid(&guest_sid, DOMAIN_USER_RID_GUEST); become_root(); - if (!pdb_getsampwsid(sampass, &guest_sid)) { - unbecome_root(); + ret = pdb_getsampwsid(sampass, &guest_sid); + unbecome_root(); + + if (!ret) { + pdb_free_sam(&sampass); return NT_STATUS_NO_SUCH_USER; } - unbecome_root(); - nt_status = make_server_info_sam(server_info, sampass); + status = make_server_info_sam(server_info, sampass); - if (NT_STATUS_IS_OK(nt_status)) { - static const char zeros[16]; - (*server_info)->guest = True; - - /* annoying, but the Guest really does have a session key, - and it is all zeros! */ - (*server_info)->user_session_key = data_blob(zeros, sizeof(zeros)); - (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros)); + if (!NT_STATUS_IS_OK(status)) { + + /* If there was no initial group mapping for the nobody user, + create one*/ + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { + GROUP_MAP map; + struct passwd *pwd = getpwnam_alloc(NULL, pdb_get_username(sampass)); + + if ( pwd == NULL ) { + DEBUG(1, ("No guest user %s!\n", + pdb_get_username(sampass))); + pdb_free_sam(&sampass); + return NT_STATUS_NO_SUCH_USER; + } + + map.gid = pwd->pw_gid; + sid_copy(&map.sid, get_global_sam_sid()); + sid_append_rid(&map.sid, DOMAIN_GROUP_RID_GUESTS); + map.sid_name_use = SID_NAME_DOM_GRP; + fstrcpy(map.nt_name, "Domain Guests"); + map.comment[0] = '\0'; + + if ( !NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map)) ) { + DEBUG(1, ("Could not update group database for guest user %s\n", + pdb_get_username(sampass) )); + talloc_free(pwd); + pdb_free_sam(&sampass); + return NT_STATUS_NO_SUCH_USER; + } + + talloc_free(pwd); + + /* And try again. */ + status = make_server_info_sam(server_info, sampass); + } + + if (!NT_STATUS_IS_OK(status)) { + pdb_free_sam(&sampass); + return status; + } } + + (*server_info)->guest = True; - return nt_status; + status = create_local_token(*server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_local_token failed: %s\n", + nt_errstr(status))); + return status; + } + + /* annoying, but the Guest really does have a session key, and it is + all zeros! */ + (*server_info)->user_session_key = data_blob(zeros, sizeof(zeros)); + (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros)); + + return NT_STATUS_OK; } static auth_serversupplied_info *copy_serverinfo(auth_serversupplied_info *src) { auth_serversupplied_info *dst; - if (!NT_STATUS_IS_OK(make_server_info(&dst))) + dst = make_server_info(NULL); + if (dst == NULL) { return NULL; + } dst->guest = src->guest; dst->uid = src->uid; dst->gid = src->gid; dst->n_groups = src->n_groups; if (src->n_groups != 0) - dst->groups = memdup(src->groups, sizeof(gid_t)*dst->n_groups); + dst->groups = talloc_memdup(dst, src->groups, + sizeof(gid_t)*dst->n_groups); else dst->groups = NULL; - dst->ptok = dup_nt_token(src->ptok); - dst->user_session_key = data_blob(src->user_session_key.data, - src->user_session_key.length); - dst->lm_session_key = data_blob(src->lm_session_key.data, - src->lm_session_key.length); + dst->ptok = dup_nt_token(dst, src->ptok); + dst->user_session_key = data_blob_talloc( + dst, src->user_session_key.data, + src->user_session_key.length); + dst->lm_session_key = data_blob_talloc( + dst, src->lm_session_key.data, + src->lm_session_key.length); pdb_copy_sam_account(src->sam_account, &dst->sam_account); dst->pam_handle = NULL; - dst->unix_name = smb_xstrdup(src->unix_name); + dst->unix_name = talloc_strdup(dst, src->unix_name); return dst; } @@ -1103,7 +1303,7 @@ static NTSTATUS fill_sam_account(TALLOC_CTX *mem_ctx, map_username( dom_user ); - if ( !(passwd = smb_getpwnam( dom_user, real_username, True )) ) + if ( !(passwd = smb_getpwnam( NULL, dom_user, real_username, True )) ) return NT_STATUS_NO_SUCH_USER; *uid = passwd->pw_uid; @@ -1121,7 +1321,7 @@ static NTSTATUS fill_sam_account(TALLOC_CTX *mem_ctx, *found_username)); nt_status = pdb_init_sam_pw(sam_account, passwd); - passwd_free(&passwd); + talloc_free(passwd); return nt_status; } @@ -1131,7 +1331,8 @@ static NTSTATUS fill_sam_account(TALLOC_CTX *mem_ctx, the username if we fallback to the username only. ****************************************************************************/ -struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) +struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, char *domuser, + fstring save_username, BOOL create ) { struct passwd *pw = NULL; char *p; @@ -1154,7 +1355,7 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) if ( p ) { fstring strip_username; - pw = Get_Pwnam_alloc( domuser ); + pw = Get_Pwnam_alloc( mem_ctx, domuser ); if ( pw ) { /* make sure we get the case of the username correct */ /* work around 'winbind use default domain = yes' */ @@ -1185,7 +1386,7 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) /* just lookup a plain username */ - pw = Get_Pwnam_alloc(username); + pw = Get_Pwnam_alloc(mem_ctx, username); /* Create local user if requested. */ @@ -1195,7 +1396,7 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) return NULL; smb_create_user(NULL, username, NULL); - pw = Get_Pwnam_alloc(username); + pw = Get_Pwnam_alloc(mem_ctx, username); } /* one last check for a valid passwd struct */ @@ -1231,15 +1432,10 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, uid_t uid; gid_t gid; - size_t n_lgroupSIDs; - DOM_SID *lgroupSIDs = NULL; - - gid_t *unix_groups = NULL; - NT_USER_TOKEN *token; - - DOM_SID *all_group_SIDs; size_t i; + auth_serversupplied_info *result; + /* Here is where we should check the list of trusted domains, and verify that the SID @@ -1257,12 +1453,14 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, } if (!(nt_username = unistr2_tdup(mem_ctx, &(info3->uni_user_name)))) { - /* If the server didn't give us one, just use the one we sent them */ + /* If the server didn't give us one, just use the one we sent + * them */ nt_username = sent_nt_username; } if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3->uni_logon_dom)))) { - /* If the server didn't give us one, just use the one we sent them */ + /* If the server didn't give us one, just use the one we sent + * them */ nt_domain = domain; } @@ -1271,21 +1469,25 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, We use the _unmapped_ username here in an attempt to provide consistent username mapping behavior between kerberos and NTLM[SSP] - authentication in domain mode security. I.E. Username mapping should - be applied to the fully qualified username (e.g. DOMAIN\user) and - no just the login name. Yes this mean swe called map_username() - unnecessarily in make_user_info_map() but that is how the current - code is designed. Making the change here is the least disruptive - place. -- jerry */ + authentication in domain mode security. I.E. Username mapping + should be applied to the fully qualified username + (e.g. DOMAIN\user) and not just the login name. Yes this means we + called map_username() unnecessarily in make_user_info_map() but + that is how the current code is designed. Making the change here + is the least disruptive place. -- jerry */ nt_status = fill_sam_account(mem_ctx, nt_domain, sent_nt_username, - &found_username, &uid, &gid, &sam_account); + &found_username, &uid, &gid, + &sam_account); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) { - DEBUG(3,("User %s does not exist, trying to add it\n", internal_username)); + DEBUG(3,("User %s does not exist, trying to add it\n", + internal_username)); smb_create_user( nt_domain, sent_nt_username, NULL); - nt_status = fill_sam_account( mem_ctx, nt_domain, sent_nt_username, - &found_username, &uid, &gid, &sam_account ); + nt_status = fill_sam_account( mem_ctx, nt_domain, + sent_nt_username, + &found_username, &uid, &gid, + &sam_account ); } /* if we still don't have a valid unix account check for @@ -1326,96 +1528,77 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - if (!pdb_set_fullname(sam_account, unistr2_static(&(info3->uni_full_name)), + if (!pdb_set_fullname(sam_account, + unistr2_static(&(info3->uni_full_name)), PDB_CHANGED)) { pdb_free_sam(&sam_account); return NT_STATUS_NO_MEMORY; } - if (!pdb_set_logon_script(sam_account, unistr2_static(&(info3->uni_logon_script)), PDB_CHANGED)) { + if (!pdb_set_logon_script(sam_account, + unistr2_static(&(info3->uni_logon_script)), + PDB_CHANGED)) { pdb_free_sam(&sam_account); return NT_STATUS_NO_MEMORY; } - if (!pdb_set_profile_path(sam_account, unistr2_static(&(info3->uni_profile_path)), PDB_CHANGED)) { + if (!pdb_set_profile_path(sam_account, + unistr2_static(&(info3->uni_profile_path)), + PDB_CHANGED)) { pdb_free_sam(&sam_account); return NT_STATUS_NO_MEMORY; } - if (!pdb_set_homedir(sam_account, unistr2_static(&(info3->uni_home_dir)), PDB_CHANGED)) { + if (!pdb_set_homedir(sam_account, + unistr2_static(&(info3->uni_home_dir)), + PDB_CHANGED)) { pdb_free_sam(&sam_account); return NT_STATUS_NO_MEMORY; } - if (!pdb_set_dir_drive(sam_account, unistr2_static(&(info3->uni_dir_drive)), PDB_CHANGED)) { + if (!pdb_set_dir_drive(sam_account, + unistr2_static(&(info3->uni_dir_drive)), + PDB_CHANGED)) { pdb_free_sam(&sam_account); return NT_STATUS_NO_MEMORY; } - if (!NT_STATUS_IS_OK(nt_status = make_server_info(server_info))) { + result = make_server_info(NULL); + if (result == NULL) { DEBUG(4, ("make_server_info failed!\n")); pdb_free_sam(&sam_account); - return nt_status; + return NT_STATUS_NO_MEMORY; } /* save this here to _net_sam_logon() doesn't fail (it assumes a valid SAM_ACCOUNT) */ - (*server_info)->sam_account = sam_account; - - (*server_info)->unix_name = smb_xstrdup(found_username); + result->sam_account = sam_account; + result->unix_name = talloc_strdup(result, found_username); /* Fill in the unix info we found on the way */ - (*server_info)->sam_fill_level = SAM_FILL_ALL; - (*server_info)->uid = uid; - (*server_info)->gid = gid; - - /* Store the user group information in the server_info - returned to the caller. */ - - nt_status = get_user_groups((*server_info)->unix_name, - uid, gid, &n_lgroupSIDs, &lgroupSIDs, &unix_groups); - - if ( !NT_STATUS_IS_OK(nt_status) ) { - DEBUG(4,("get_user_groups failed\n")); - return nt_status; - } + result->uid = uid; + result->gid = gid; - (*server_info)->groups = unix_groups; - (*server_info)->n_groups = n_lgroupSIDs; - /* Create a 'combined' list of all SIDs we might want in the SD */ - - all_group_SIDs = SMB_MALLOC_ARRAY(DOM_SID,info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs); - - if (!all_group_SIDs) { - DEBUG(0, ("malloc() failed for DOM_SID list!\n")); - SAFE_FREE(lgroupSIDs); - free_server_info(server_info); - return NT_STATUS_NO_MEMORY; - } + + result->num_sids = 0; + result->sids = NULL; /* and create (by appending rids) the 'domain' sids */ for (i = 0; i < info3->num_groups2; i++) { - - sid_copy(&all_group_SIDs[i], &(info3->dom_sid.sid)); - - if (!sid_append_rid(&all_group_SIDs[i], info3->gids[i].g_rid)) { - - nt_status = NT_STATUS_INVALID_PARAMETER; - - DEBUG(3,("could not append additional group rid 0x%x\n", - info3->gids[i].g_rid)); - - SAFE_FREE(lgroupSIDs); - SAFE_FREE(all_group_SIDs); - free_server_info(server_info); - - return nt_status; - + DOM_SID sid; + if (!sid_compose(&sid, &info3->dom_sid.sid, + info3->gids[i].g_rid)) { + DEBUG(3,("could not append additional group rid " + "0x%x\n", info3->gids[i].g_rid)); + talloc_free(result); + return NT_STATUS_INVALID_PARAMETER; } + add_sid_to_array(result, &sid, &result->sids, + &result->num_sids); } /* Copy 'other' sids. We need to do sid filtering here to @@ -1425,56 +1608,33 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, */ for (i = 0; i < info3->num_other_sids; i++) { - sid_copy(&all_group_SIDs[info3->num_groups2 + i], - &info3->other_sids[i].sid); - } - - - /* add local alias sids */ - - for (i = 0; i < n_lgroupSIDs; i++) { - sid_copy(&all_group_SIDs[info3->num_groups2 + - info3->num_other_sids + i], - &lgroupSIDs[i]); - } - - /* Where are the 'global' sids... */ - - /* can the user be guest? if yes, where is it stored? */ - - nt_status = create_nt_user_token(&user_sid, &group_sid, - info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs, - all_group_SIDs, False, &token); - - if ( !NT_STATUS_IS_OK(nt_status) ) { - DEBUG(4,("create_nt_user_token failed\n")); - SAFE_FREE(lgroupSIDs); - SAFE_FREE(all_group_SIDs); - free_server_info(server_info); - return nt_status; + add_sid_to_array(result, &info3->other_sids[i].sid, + &result->sids, + &result->num_sids); } - (*server_info)->login_server = unistr2_tdup(mem_ctx, - &(info3->uni_logon_srv)); - - (*server_info)->ptok = token; - - SAFE_FREE(lgroupSIDs); - SAFE_FREE(all_group_SIDs); + result->login_server = unistr2_tdup(result, + &(info3->uni_logon_srv)); /* ensure we are never given NULL session keys */ if (memcmp(info3->user_sess_key, zeros, sizeof(zeros)) == 0) { - (*server_info)->user_session_key = data_blob(NULL, 0); + result->user_session_key = data_blob(NULL, 0); } else { - (*server_info)->user_session_key = data_blob(info3->user_sess_key, sizeof(info3->user_sess_key)); + result->user_session_key = data_blob_talloc( + result, info3->user_sess_key, + sizeof(info3->user_sess_key)); } if (memcmp(info3->lm_sess_key, zeros, 8) == 0) { - (*server_info)->lm_session_key = data_blob(NULL, 0); + result->lm_session_key = data_blob(NULL, 0); } else { - (*server_info)->lm_session_key = data_blob(info3->lm_sess_key, sizeof(info3->lm_sess_key)); - } + result->lm_session_key = data_blob_talloc( + result, info3->lm_sess_key, + sizeof(info3->lm_sess_key)); + } + + *server_info = result; return NT_STATUS_OK; } @@ -1487,14 +1647,15 @@ void free_user_info(auth_usersupplied_info **user_info) { DEBUG(5,("attempting to free (and zero) a user_info structure\n")); if (*user_info != NULL) { - if ((*user_info)->smb_name.str) { - DEBUG(10,("structure was created for %s\n", (*user_info)->smb_name.str)); + if ((*user_info)->smb_name) { + DEBUG(10,("structure was created for %s\n", + (*user_info)->smb_name)); } - SAFE_FREE((*user_info)->smb_name.str); - SAFE_FREE((*user_info)->internal_username.str); - SAFE_FREE((*user_info)->client_domain.str); - SAFE_FREE((*user_info)->domain.str); - SAFE_FREE((*user_info)->wksta_name.str); + SAFE_FREE((*user_info)->smb_name); + SAFE_FREE((*user_info)->internal_username); + SAFE_FREE((*user_info)->client_domain); + SAFE_FREE((*user_info)->domain); + SAFE_FREE((*user_info)->wksta_name); data_blob_free(&(*user_info)->lm_resp); data_blob_free(&(*user_info)->nt_resp); data_blob_clear_free(&(*user_info)->lm_interactive_pwd); @@ -1505,27 +1666,6 @@ void free_user_info(auth_usersupplied_info **user_info) SAFE_FREE(*user_info); } -/*************************************************************************** - Clear out a server_info struct that has been allocated -***************************************************************************/ - -void free_server_info(auth_serversupplied_info **server_info) -{ - DEBUG(5,("attempting to free (and zero) a server_info structure\n")); - if (*server_info != NULL) { - pdb_free_sam(&(*server_info)->sam_account); - - /* call pam_end here, unless we know we are keeping it */ - delete_nt_token( &(*server_info)->ptok ); - SAFE_FREE((*server_info)->groups); - SAFE_FREE((*server_info)->unix_name); - data_blob_free(&(*server_info)->lm_session_key); - data_blob_free(&(*server_info)->user_session_key); - ZERO_STRUCT(**server_info); - } - SAFE_FREE(*server_info); -} - /*************************************************************************** Make an auth_methods struct ***************************************************************************/ @@ -1533,11 +1673,13 @@ void free_server_info(auth_serversupplied_info **server_info) BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_method) { if (!auth_context) { - smb_panic("no auth_context supplied to make_auth_methods()!\n"); + smb_panic("no auth_context supplied to " + "make_auth_methods()!\n"); } if (!auth_method) { - smb_panic("make_auth_methods: pointer to auth_method pointer is NULL!\n"); + smb_panic("make_auth_methods: pointer to auth_method pointer " + "is NULL!\n"); } *auth_method = TALLOC_P(auth_context->mem_ctx, auth_methods); @@ -1550,41 +1692,29 @@ BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_me return True; } -/**************************************************************************** - Delete a SID token. -****************************************************************************/ - -void delete_nt_token(NT_USER_TOKEN **pptoken) -{ - if (*pptoken) { - NT_USER_TOKEN *ptoken = *pptoken; - - SAFE_FREE( ptoken->user_sids ); - ZERO_STRUCTP(ptoken); - } - SAFE_FREE(*pptoken); -} - /**************************************************************************** Duplicate a SID token. ****************************************************************************/ -NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) +NT_USER_TOKEN *dup_nt_token(TALLOC_CTX *mem_ctx, NT_USER_TOKEN *ptoken) { NT_USER_TOKEN *token; if (!ptoken) return NULL; - if ((token = SMB_MALLOC_P(NT_USER_TOKEN)) == NULL) + token = TALLOC_P(mem_ctx, NT_USER_TOKEN); + if (token == NULL) { + DEBUG(0, ("talloc failed\n")); return NULL; + } - ZERO_STRUCTP(token); - - token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids ); - - if ( !token ) { - SAFE_FREE(token); + token->user_sids = talloc_memdup(token, ptoken->user_sids, + sizeof(DOM_SID) * ptoken->num_sids ); + + if ((ptoken->user_sids != NULL) && (token->user_sids == NULL)) { + DEBUG(0, ("talloc_memdup failed\n")); + talloc_free(token); return NULL; } @@ -1593,7 +1723,8 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) /* copy the privileges; don't consider failure to be critical here */ if ( !se_priv_copy( &token->privileges, &ptoken->privileges ) ) { - DEBUG(0,("dup_nt_token: Failure to copy SE_PRIV!. Continuing with 0 privileges assigned.\n")); + DEBUG(0,("dup_nt_token: Failure to copy SE_PRIV!. " + "Continuing with 0 privileges assigned.\n")); } return token; @@ -1603,7 +1734,7 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) Check for a SID in an NT_USER_TOKEN ****************************************************************************/ -static BOOL nt_token_check_sid ( DOM_SID *sid, NT_USER_TOKEN *token ) +BOOL nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token ) { int i; @@ -1626,9 +1757,10 @@ BOOL nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid ) a DC or standalone server, use our own SID */ if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) { - if ( !secrets_fetch_domain_sid( lp_workgroup(), &domain_sid ) ) { - DEBUG(1,("nt_token_check_domain_rid: Cannot lookup SID for domain [%s]\n", - lp_workgroup())); + if ( !secrets_fetch_domain_sid( lp_workgroup(), + &domain_sid ) ) { + DEBUG(1,("nt_token_check_domain_rid: Cannot lookup " + "SID for domain [%s]\n", lp_workgroup())); return False; } } @@ -1662,9 +1794,10 @@ BOOL is_trusted_domain(const char* dom_name) if ( IS_DC ) { become_root(); - DEBUG (5,("is_trusted_domain: Checking for domain trust with [%s]\n", - dom_name )); - ret = secrets_fetch_trusted_domain_password(dom_name, NULL, NULL, NULL); + DEBUG (5,("is_trusted_domain: Checking for domain trust with " + "[%s]\n", dom_name )); + ret = secrets_fetch_trusted_domain_password(dom_name, NULL, + NULL, NULL); unbecome_root(); if (ret) return True; diff --git a/source/auth/auth_winbind.c b/source/auth/auth_winbind.c index ad72bd9a1fd..6e2f26a5722 100644 --- a/source/auth/auth_winbind.c +++ b/source/auth/auth_winbind.c @@ -71,13 +71,13 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, if (!auth_context) { DEBUG(3,("Password for user %s cannot be checked because we have no auth_info to get the challenge from.\n", - user_info->internal_username.str)); + user_info->internal_username)); return NT_STATUS_INVALID_PARAMETER; } - if (strequal(user_info->domain.str, get_global_sam_name())) { + if (strequal(user_info->domain, get_global_sam_name())) { DEBUG(3,("check_winbind_security: Not using winbind, requested domain [%s] was for this SAM.\n", - user_info->domain.str)); + user_info->domain)); return NT_STATUS_NOT_IMPLEMENTED; } @@ -90,12 +90,9 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, request.data.auth_crap.logon_parameters = user_info->logon_parameters; - fstrcpy(request.data.auth_crap.user, - user_info->smb_name.str); - fstrcpy(request.data.auth_crap.domain, - user_info->domain.str); - fstrcpy(request.data.auth_crap.workstation, - user_info->wksta_name.str); + fstrcpy(request.data.auth_crap.user, user_info->smb_name); + fstrcpy(request.data.auth_crap.domain, user_info->domain); + fstrcpy(request.data.auth_crap.workstation, user_info->wksta_name); memcpy(request.data.auth_crap.chal, auth_context->challenge.data, sizeof(request.data.auth_crap.chal)); @@ -131,8 +128,8 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, if (NT_STATUS_IS_OK(nt_status)) { if (NT_STATUS_IS_OK(nt_status = get_info3_from_ndr(mem_ctx, &response, &info3))) { nt_status = make_server_info_info3(mem_ctx, - user_info->internal_username.str, - user_info->smb_name.str, user_info->domain.str, + user_info->internal_username, + user_info->smb_name, user_info->domain, server_info, &info3); } diff --git a/source/configure.in b/source/configure.in index 7079bf7437a..e901e065d27 100644 --- a/source/configure.in +++ b/source/configure.in @@ -462,7 +462,7 @@ DYNEXP= dnl Add modules that have to be built by default here dnl These have to be built static: -default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_reg rpc_lsa_ds rpc_wks rpc_svcctl rpc_ntsvcs rpc_net rpc_dfs rpc_srv rpc_spoolss rpc_eventlog auth_rhosts auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin" +default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_reg rpc_lsa_ds rpc_wks rpc_svcctl rpc_ntsvcs rpc_net rpc_netdfs rpc_srv rpc_spoolss rpc_eventlog auth_rhosts auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin" dnl These are preferably build shared, and static if dlopen() is not available default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy charset_CP850 charset_CP437 auth_script" @@ -2871,6 +2871,8 @@ if test x"$with_ldap_support" != x"no"; then AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc]) + AC_CHECK_FUNC_EXT(ldap_dn2ad_canonical,$LDAP_LIBS) + if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes"; then AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available]) CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED" @@ -3144,6 +3146,9 @@ if test x"$with_ads_support" != x"no"; then AC_CHECK_FUNC_EXT(krb5_principal_compare_any_realm, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_parse_name_norealm, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_princ_size, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_set_pac_request, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_get_renewed_creds, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_get_kdc_cred, $KRB5_LIBS) LIBS="$KRB5_LIBS $LIBS" @@ -3445,6 +3450,29 @@ if test x"$with_ads_support" != x"no"; then LIBS="$ac_save_LIBS" fi +################################################# +# check for KCM support + +with_kcm_support=no +AC_MSG_CHECKING([for KCM support]) + +AC_ARG_WITH(kcm, +[ --with-kcm KCM support (default no)], +[ case "$withval" in + yes) + if test x$FOUND_KRB5 = x"no"; then + AC_MSG_ERROR(libkrb5 is needed for KCM support) + fi + with_kcm_support="$withval" + AC_DEFINE(WITH_KCM,1,[Whether to include KCM support]) + ;; + *) + with_kcm_support="no" + AC_DEFINE(WITH_KCM,0,[Whether to include KCM support]) + ;; + esac ]) + +AC_MSG_RESULT($with_kcm_support) ######################################################## # Compile experimental passdb backends? # (pdb_xml, pdb_mysql, pdb_pgsql) @@ -5177,7 +5205,7 @@ SMB_MODULE(rpc_wks, \$(RPC_WKS_OBJ), "bin/librpc_wkssvc.$SHLIBEXT", RPC) SMB_MODULE(rpc_svcctl, \$(RPC_SVCCTL_OBJ), "bin/librpc_svcctl.$SHLIBEXT", RPC) SMB_MODULE(rpc_ntsvcs, \$(RPC_NTSVCS_OBJ), "bin/librpc_ntsvcs.$SHLIBEXT", RPC) SMB_MODULE(rpc_net, \$(RPC_NETLOG_OBJ), "bin/librpc_NETLOGON.$SHLIBEXT", RPC) -SMB_MODULE(rpc_dfs, \$(RPC_DFS_OBJ), "bin/librpc_netdfs.$SHLIBEXT", RPC) +SMB_MODULE(rpc_netdfs, \$(RPC_DFS_OBJ), "bin/librpc_netdfs.$SHLIBEXT", RPC) SMB_MODULE(rpc_srv, \$(RPC_SVC_OBJ), "bin/librpc_srvsvc.$SHLIBEXT", RPC) SMB_MODULE(rpc_spoolss, \$(RPC_SPOOLSS_OBJ), "bin/librpc_spoolss.$SHLIBEXT", RPC) SMB_MODULE(rpc_eventlog, \$(RPC_EVENTLOG_OBJ), "bin/librpc_eventlog.$SHLIBEXT", RPC) diff --git a/source/groupdb/mapping.c b/source/groupdb/mapping.c index 7dc0426c449..2790d475877 100644 --- a/source/groupdb/mapping.c +++ b/source/groupdb/mapping.c @@ -176,7 +176,65 @@ BOOL add_initial_entry(gid_t gid, const char *sid, enum SID_NAME_USE sid_name_us fstrcpy(map.nt_name, nt_name); fstrcpy(map.comment, comment); - return pdb_add_group_mapping_entry(&map); + return NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map)); +} + +/**************************************************************************** + Map a unix group to a newly created mapping +****************************************************************************/ +NTSTATUS map_unix_group(const struct group *grp, GROUP_MAP *pmap) +{ + NTSTATUS status; + GROUP_MAP map; + const char *grpname, *dom, *name; + uint32 rid; + + if (pdb_getgrgid(&map, grp->gr_gid)) { + return NT_STATUS_GROUP_EXISTS; + } + + map.gid = grp->gr_gid; + grpname = grp->gr_name; + + if (lookup_name(tmp_talloc_ctx(), grpname, LOOKUP_NAME_ISOLATED, + &dom, &name, NULL, NULL)) { + + const char *tmp = talloc_asprintf( + tmp_talloc_ctx(), "Unix Group %s", grp->gr_name); + + DEBUG(5, ("%s exists as %s\\%s, retrying as \"%s\"\n", + grpname, dom, name, tmp)); + grpname = tmp; + } + + if (lookup_name(tmp_talloc_ctx(), grpname, LOOKUP_NAME_ISOLATED, + NULL, NULL, NULL, NULL)) { + DEBUG(3, ("\"%s\" exists, can't map it\n", grp->gr_name)); + return NT_STATUS_GROUP_EXISTS; + } + + fstrcpy(map.nt_name, grpname); + + if (pdb_rid_algorithm()) { + rid = pdb_gid_to_group_rid( grp->gr_gid ); + } else { + if (!pdb_new_rid(&rid)) { + DEBUG(3, ("Could not get a new RID for %s\n", + grp->gr_name)); + return NT_STATUS_ACCESS_DENIED; + } + } + + sid_compose(&map.sid, get_global_sam_sid(), rid); + map.sid_name_use = SID_NAME_DOM_GRP; + fstrcpy(map.comment, talloc_asprintf(tmp_talloc_ctx(), "Unix Group %s", + grp->gr_name)); + + status = pdb_add_group_mapping_entry(&map); + if (NT_STATUS_IS_OK(status)) { + *pmap = map; + } + return status; } /**************************************************************************** @@ -794,99 +852,6 @@ BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map) return True; } - -/* get a local (alias) group from it's SID */ - -BOOL get_local_group_from_sid(DOM_SID *sid, GROUP_MAP *map) -{ - BOOL ret; - - if(!init_group_mapping()) { - DEBUG(0,("failed to initialize group mapping\n")); - return(False); - } - - /* The group is in the mapping table */ - become_root(); - ret = pdb_getgrsid(map, *sid); - unbecome_root(); - - if ( !ret ) - return False; - - if ( ( (map->sid_name_use != SID_NAME_ALIAS) && - (map->sid_name_use != SID_NAME_WKN_GRP) ) - || (map->gid == -1) - || (getgrgid(map->gid) == NULL) ) - { - return False; - } - -#if 1 /* JERRY */ - /* local groups only exist in the group mapping DB so this - is not necessary */ - - else { - /* the group isn't in the mapping table. - * make one based on the unix information */ - uint32 alias_rid; - struct group *grp; - - sid_peek_rid(sid, &alias_rid); - map->gid=pdb_group_rid_to_gid(alias_rid); - - grp = getgrgid(map->gid); - if ( !grp ) { - DEBUG(3,("get_local_group_from_sid: No unix group for [%ul]\n", map->gid)); - return False; - } - - map->sid_name_use=SID_NAME_ALIAS; - - fstrcpy(map->nt_name, grp->gr_name); - fstrcpy(map->comment, "Local Unix Group"); - - sid_copy(&map->sid, sid); - } -#endif - - return True; -} - -/* get a builtin group from it's SID */ - -BOOL get_builtin_group_from_sid(DOM_SID *sid, GROUP_MAP *map) -{ - BOOL ret; - - - if(!init_group_mapping()) { - DEBUG(0,("failed to initialize group mapping\n")); - return(False); - } - - become_root(); - ret = pdb_getgrsid(map, *sid); - unbecome_root(); - - if ( !ret ) - return False; - - if (map->sid_name_use!=SID_NAME_WKN_GRP) { - return False; - } - - if (map->gid==-1) { - return False; - } - - if ( getgrgid(map->gid) == NULL) { - return False; - } - - return True; -} - /**************************************************************************** Create a UNIX group on demand. ****************************************************************************/ @@ -1101,9 +1066,12 @@ NTSTATUS pdb_default_create_alias(struct pdb_methods *methods, gid_t gid; BOOL exists; GROUP_MAP map; + TALLOC_CTX *mem_ctx; + NTSTATUS status; - TALLOC_CTX *mem_ctx = talloc_new(NULL); + DEBUG(10, ("Trying to create alias %s\n", name)); + mem_ctx = talloc_new(NULL); if (mem_ctx == NULL) { return NT_STATUS_NO_MEMORY; } @@ -1116,8 +1084,18 @@ NTSTATUS pdb_default_create_alias(struct pdb_methods *methods, return NT_STATUS_ALIAS_EXISTS; } - if (!winbind_allocate_rid_and_gid(&new_rid, &gid)) + if (!winbind_allocate_gid(&gid)) { + DEBUG(3, ("Could not get a gid out of winbind\n")); + return NT_STATUS_ACCESS_DENIED; + } + + if (!pdb_new_rid(&new_rid)) { + DEBUG(0, ("Could not allocate a RID -- wasted a gid :-(\n")); return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(10, ("Creating alias %s with gid %d and rid %d\n", + name, gid, new_rid)); sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, new_rid); @@ -1128,10 +1106,12 @@ NTSTATUS pdb_default_create_alias(struct pdb_methods *methods, fstrcpy(map.nt_name, name); fstrcpy(map.comment, ""); - if (!pdb_add_group_mapping_entry(&map)) { - DEBUG(0, ("Could not add group mapping entry for alias %s\n", - name)); - return NT_STATUS_ACCESS_DENIED; + status = pdb_add_group_mapping_entry(&map); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Could not add group mapping entry for alias %s " + "(%s)\n", name, nt_errstr(status))); + return status; } *rid = new_rid; @@ -1155,6 +1135,14 @@ NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods, if (!pdb_getgrsid(&map, *sid)) return NT_STATUS_NO_SUCH_ALIAS; + if ((map.sid_name_use != SID_NAME_ALIAS) && + (map.sid_name_use != SID_NAME_WKN_GRP)) { + DEBUG(2, ("%s is a %s, expected an alias\n", + sid_string_static(sid), + sid_type_lookup(map.sid_name_use))); + return NT_STATUS_NO_SUCH_ALIAS; + } + fstrcpy(info->acct_name, map.nt_name); fstrcpy(info->acct_desc, map.comment); sid_peek_rid(&map.sid, &info->rid); @@ -1172,10 +1160,7 @@ NTSTATUS pdb_default_set_aliasinfo(struct pdb_methods *methods, fstrcpy(map.comment, info->acct_desc); - if (!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_ACCESS_DENIED; - - return NT_STATUS_OK; + return pdb_update_group_mapping_entry(&map); } NTSTATUS pdb_default_add_aliasmem(struct pdb_methods *methods, @@ -1315,7 +1300,7 @@ BOOL pdb_set_dom_grp_info(const DOM_SID *sid, const struct acct_info *info) fstrcpy(map.nt_name, info->acct_name); fstrcpy(map.comment, info->acct_desc); - return pdb_update_group_mapping_entry(&map); + return NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map)); } diff --git a/source/include/ads.h b/source/include/ads.h index decb823ea99..ce643666ad9 100644 --- a/source/include/ads.h +++ b/source/include/ads.h @@ -30,6 +30,7 @@ typedef struct { unsigned flags; int time_offset; time_t expire; + time_t renewable; } auth; /* info derived from the servers config */ @@ -91,6 +92,7 @@ typedef void **ADS_MODLIST; #define ADS_NO_REFERRALS_OID "1.2.840.113556.1.4.1339" #define ADS_SERVER_SORT_OID "1.2.840.113556.1.4.473" #define ADS_PERMIT_MODIFY_OID "1.2.840.113556.1.4.1413" +#define ADS_ASQ_OID "1.2.840.113556.1.4.1504" /* ldap attribute oids (Services for Unix) */ #define ADS_ATTR_SFU_UIDNUMBER_OID "1.2.840.113556.1.6.18.1.310" diff --git a/source/include/auth.h b/source/include/auth.h index 03206c03c6a..79fbb93895f 100644 --- a/source/include/auth.h +++ b/source/include/auth.h @@ -20,12 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* AUTH_STR - string */ -typedef struct normal_string { - int len; - char *str; -} AUTH_STR; - typedef struct auth_usersupplied_info { DATA_BLOB lm_resp; DATA_BLOB nt_resp; @@ -35,25 +29,24 @@ typedef struct auth_usersupplied_info { BOOL encrypted; - AUTH_STR client_domain; /* domain name string */ - AUTH_STR domain; /* domain name after mapping */ - AUTH_STR internal_username; /* username after mapping */ - AUTH_STR smb_name; /* username before mapping */ - AUTH_STR wksta_name; /* workstation name (netbios calling name) unicode string */ + char *client_domain; /* domain name string */ + char *domain; /* domain name after mapping */ + char *internal_username; /* username after mapping */ + char *smb_name; /* username before mapping */ + char *wksta_name; /* workstation name (netbios calling + * name) unicode string */ uint32 logon_parameters; } auth_usersupplied_info; -#define SAM_FILL_NAME 0x01 -#define SAM_FILL_INFO3 0x02 -#define SAM_FILL_SAM 0x04 -#define SAM_FILL_UNIX 0x08 -#define SAM_FILL_ALL (SAM_FILL_NAME | SAM_FILL_INFO3 | SAM_FILL_SAM | SAM_FILL_UNIX) - typedef struct auth_serversupplied_info { BOOL guest; + DOM_SID *sids; /* These SIDs are preliminary between + check_ntlm_password and the token creation. */ + size_t num_sids; + uid_t uid; gid_t gid; @@ -70,8 +63,6 @@ typedef struct auth_serversupplied_info { char *login_server; /* which server authorized the login? */ - uint32 sam_fill_level; /* How far is this structure filled? */ - SAM_ACCOUNT *sam_account; void *pam_handle; diff --git a/source/include/doserr.h b/source/include/doserr.h index 62c1e4fa22d..8f8ea066964 100644 --- a/source/include/doserr.h +++ b/source/include/doserr.h @@ -200,6 +200,7 @@ #define WERR_SERVICE_NEVER_STARTED W_ERROR(1077) #define WERR_MACHINE_LOCKED W_ERROR(1271) #define WERR_INVALID_SECURITY_DESCRIPTOR W_ERROR(1338) +#define WERR_TIME_SKEW W_ERROR(1398) #define WERR_EVENTLOG_FILE_CORRUPT W_ERROR(1500) #define WERR_SERVER_UNAVAILABLE W_ERROR(1722) #define WERR_INVALID_FORM_NAME W_ERROR(1902) diff --git a/source/include/event.h b/source/include/event.h new file mode 100644 index 00000000000..fdb990678db --- /dev/null +++ b/source/include/event.h @@ -0,0 +1,31 @@ +/* + Unix SMB/CIFS implementation. + event handling + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Volker Lendecke 2005 + + 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. +*/ + +struct timed_event { + struct timed_event *next, *prev; + struct timeval when; + const char *event_name; + void (*handler)(struct timed_event *te, + const struct timeval *now, + void *private_data); + void *private_data; +}; + diff --git a/source/include/gpo.h b/source/include/gpo.h new file mode 100644 index 00000000000..65c96c31e6b --- /dev/null +++ b/source/include/gpo.h @@ -0,0 +1,91 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Guenther Deschner 2005 + * + * 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. + */ + + +enum GPO_LINK_TYPE { + GP_LINK_UNKOWN, + GP_LINK_MACHINE, + GP_LINK_SITE, + GP_LINK_DOMAIN, + GP_LINK_OU +}; + +/* GPO_OPTIONS */ +#define GPO_FLAG_DISABLE 0x00000001 +#define GPO_FLAG_FORCE 0x00000002 + +/* GPO_LIST_FLAGS */ +#define GPO_LIST_FLAG_MACHINE 0x00000001 +#define GPO_LIST_FLAG_SITEONLY 0x00000002 + +struct GROUP_POLICY_OBJECT { + uint32 options; /* GPFLAGS_* */ + uint32 version; + uint16 version_user; + uint16 version_machine; + const char *ds_path; + const char *file_sys_path; + const char *display_name; + const char *name; + const char *link; + uint32 link_type; /* GPO_LINK_TYPE */ + const char *user_extensions; + const char *machine_extensions; + struct GROUP_POLICY_OBJECT *next, *prev; +}; + +/* the following is seen on the DS (see adssearch.pl for details) */ + +/* the type field in a 'gPLink', the same as GPO_FLAG ? */ +#define GPO_LINK_OPT_NONE 0x00000000 +#define GPO_LINK_OPT_DISABLED 0x00000001 +#define GPO_LINK_OPT_ENFORCED 0x00000002 + +/* GPO_LINK_OPT_ENFORCED takes precedence over GPOPTIONS_BLOCK_INHERITANCE */ + +/* 'gPOptions', maybe a bitmask as well */ +enum GPO_INHERIT { + GPOPTIONS_INHERIT, + GPOPTIONS_BLOCK_INHERITANCE +}; + +/* 'flags' in a 'groupPolicyContainer' object */ +#define GPFLAGS_ALL_ENABLED 0x00000000 +#define GPFLAGS_USER_SETTINGS_DISABLED 0x00000001 +#define GPFLAGS_MACHINE_SETTINGS_DISABLED 0x00000002 +#define GPFLAGS_ALL_DISABLED (GPFLAGS_USER_SETTINGS_DISABLED | \ + GPFLAGS_MACHINE_SETTINGS_DISABLED) + +struct GP_LINK { + const char *gp_link; /* raw link name */ + uint32 gp_opts; /* inheritance options GPO_INHERIT */ + uint32 num_links; /* number of links */ + char **link_names; /* array of parsed link names */ + uint32 *link_opts; /* array of parsed link opts GPO_LINK_OPT_* */ +}; + +struct GP_EXT { + const char *gp_extension; /* raw extension name */ + uint32 num_exts; + char **extensions; + char **extensions_guid; + char **snapins; + char **snapins_guid; +}; diff --git a/source/include/idmap.h b/source/include/idmap.h index c81b94a718a..474982f2926 100644 --- a/source/include/idmap.h +++ b/source/include/idmap.h @@ -24,6 +24,9 @@ Boston, MA 02111-1307, USA. */ +/* idmap version determines auto-conversion */ +#define IDMAP_VERSION 2 + #define SMB_IDMAP_INTERFACE_VERSION 2 @@ -43,7 +46,6 @@ struct idmap_methods { /* Called when backend is first loaded */ NTSTATUS (*init)( char *params ); - NTSTATUS (*allocate_rid)(uint32 *rid, int rid_type); NTSTATUS (*allocate_id)(unid_t *id, int id_type); NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, int id_type); NTSTATUS (*get_id_from_sid)(unid_t *id, int *id_type, const DOM_SID *sid); diff --git a/source/include/includes.h b/source/include/includes.h index a9b792d5f67..8aa10032408 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -989,6 +989,8 @@ extern int errno; #include "rpc_client.h" +#include "event.h" + /* * Type for wide character dirent structure. * Only d_name is defined by POSIX. @@ -1018,6 +1020,11 @@ struct functable { int (*fn)(int argc, const char **argv); }; +struct functable2 { + const char *funcname; + int (*fn)(int argc, const char **argv); + const char *helptext; +}; /* Defines for wisXXX functions. */ #define UNI_UPPER 0x1 @@ -1508,8 +1515,10 @@ BOOL smb_krb5_principal_compare_any_realm(krb5_context context, krb5_const_principal princ1, krb5_const_principal princ2); int cli_krb5_get_ticket(const char *principal, time_t time_offset, - DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts); + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, const char *ccname); PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data); +krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, const char *client_string, const char *service_string, time_t *new_start_time); +krb5_error_code kpasswd_err_to_krb5_err(krb5_error_code res_code); #endif /* HAVE_KRB5 */ diff --git a/source/include/local.h b/source/include/local.h index c9b54ab1a21..916fb6e46d3 100644 --- a/source/include/local.h +++ b/source/include/local.h @@ -238,4 +238,13 @@ /* tdb hash size for the open database. */ #define SMB_OPEN_DATABASE_TDB_HASH_SIZE 1049 +/* Characters we disallow in sharenames. */ +#define INVALID_SHARENAME_CHARS "%<>*?|/\\+=;:\"," + +/* Seconds between connection attempts to a remote server. */ +#define FAILED_CONNECTION_CACHE_TIMEOUT 30 + +/* Default hash size for the winbindd cache. */ +#define WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE 5000 + #endif diff --git a/source/include/messages.h b/source/include/messages.h index 4b1732d42d1..dc4f4ca2c03 100644 --- a/source/include/messages.h +++ b/source/include/messages.h @@ -73,6 +73,8 @@ /* winbind messages */ #define MSG_WINBIND_FINISHED 4001 #define MSG_WINBIND_FORGET_STATE 4002 +#define MSG_WINBIND_ONLINE 4003 +#define MSG_WINBIND_OFFLINE 4004 /* Flags to classify messages - used in message_send_all() */ /* Sender will filter by flag. */ diff --git a/source/include/nt_status.h b/source/include/nt_status.h index ab768258df1..14c83eba4b3 100644 --- a/source/include/nt_status.h +++ b/source/include/nt_status.h @@ -61,4 +61,10 @@ typedef uint32 WERROR; #define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0) #define W_ERROR_EQUAL(x,y) (W_ERROR_V(x) == W_ERROR_V(y)) +#define NT_STATUS_HAVE_NO_MEMORY(x) do { \ + if (!(x)) {\ + return NT_STATUS_NO_MEMORY;\ + }\ +} while (0) + #endif diff --git a/source/include/passdb.h b/source/include/passdb.h index f1896710dc9..0035fc5b05e 100644 --- a/source/include/passdb.h +++ b/source/include/passdb.h @@ -304,9 +304,10 @@ typedef struct pdb_context size_t *p_num_members); NTSTATUS (*pdb_enum_group_memberships)(struct pdb_context *context, - const char *username, - gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups); NTSTATUS (*pdb_find_alias)(struct pdb_context *context, @@ -376,6 +377,15 @@ typedef struct pdb_context BOOL (*pdb_search_aliases)(struct pdb_context *context, struct pdb_search *search, const DOM_SID *sid); + BOOL (*pdb_uid_to_rid)(struct pdb_context *context, + uid_t uid, uint32 *rid); + BOOL (*pdb_gid_to_sid)(struct pdb_context *context, + uid_t gid, DOM_SID *sid); + BOOL (*pdb_sid_to_id)(struct pdb_context *context, const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type); + + BOOL (*pdb_rid_algorithm)(struct pdb_context *context); + BOOL (*pdb_new_rid)(struct pdb_context *context, uint32 *rid); void (*free_fn)(struct pdb_context **); @@ -439,8 +449,8 @@ typedef struct pdb_methods size_t *p_num_members); NTSTATUS (*enum_group_memberships)(struct pdb_methods *methods, - const char *username, - gid_t primary_gid, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, DOM_SID **pp_sids, gid_t **pp_gids, size_t *p_num_groups); @@ -507,6 +517,16 @@ typedef struct pdb_methods struct pdb_search *search, const DOM_SID *sid); + BOOL (*uid_to_rid)(struct pdb_methods *methods, uid_t uid, + uint32 *rid); + BOOL (*gid_to_sid)(struct pdb_methods *methods, gid_t gid, + DOM_SID *sid); + BOOL (*sid_to_id)(struct pdb_methods *methods, const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type); + + BOOL (*rid_algorithm)(struct pdb_methods *methods); + BOOL (*new_rid)(struct pdb_methods *methods, uint32 *rid); + void *private_data; /* Private data of some kind */ void (*free_private_data)(void **); diff --git a/source/include/rpc_dfs.h b/source/include/rpc_dfs.h index 7aee208c14b..adf25c9938b 100644 --- a/source/include/rpc_dfs.h +++ b/source/include/rpc_dfs.h @@ -1,164 +1,396 @@ -/* - Unix SMB/CIFS implementation. - Samba parameters and setup - Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Luke Kenneth Casson Leighton 1996 - 2000 - Copyright (C) Shirish Kalele 2000 - - 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. -*/ - -#ifndef _RPC_DFS_H -#define _RPC_DFS_H - -/* NETDFS pipe: calls */ -#define DFS_EXIST 0x00 -#define DFS_ADD 0x01 -#define DFS_REMOVE 0x02 -#define DFS_GET_INFO 0x04 -#define DFS_ENUM 0x05 - -/* dfsadd flags */ -#define DFSFLAG_ADD_VOLUME 0x00000001 -#define DFSFLAG_RESTORE_VOLUME 0x00000002 - -typedef struct dfs_q_dfs_exist { - uint32 dummy; -} DFS_Q_DFS_EXIST; - -/* status == 1 if dfs exists. */ -typedef struct dfs_r_dfs_exist { - uint32 status; /* Not a WERROR or NTSTATUS code */ -} DFS_R_DFS_EXIST; - -typedef struct dfs_q_dfs_add { - uint32 ptr_DfsEntryPath; - UNISTR2 DfsEntryPath; - uint32 ptr_ServerName; - UNISTR2 ServerName; - uint32 ptr_ShareName; - UNISTR2 ShareName; - uint32 ptr_Comment; - UNISTR2 Comment; - uint32 Flags; -} DFS_Q_DFS_ADD; - -typedef struct dfs_r_dfs_add { - WERROR status; -} DFS_R_DFS_ADD; - -/********************************************/ -typedef struct dfs_q_dfs_remove { - UNISTR2 DfsEntryPath; - uint32 ptr_ServerName; - UNISTR2 ServerName; - uint32 ptr_ShareName; - UNISTR2 ShareName; -} DFS_Q_DFS_REMOVE; - -typedef struct dfs_r_dfs_remove { - WERROR status; -} DFS_R_DFS_REMOVE; - -/********************************************/ -typedef struct dfs_info_1 { - uint32 ptr_entrypath; - UNISTR2 entrypath; -} DFS_INFO_1; - -typedef struct dfs_info_2 { - uint32 ptr_entrypath; - UNISTR2 entrypath; - uint32 ptr_comment; +/* + * Unix SMB/CIFS implementation. + * header auto-generated by pidl. DO NOT MODIFY! + */ + + +#ifndef _RPC_NETDFS_H +#define _RPC_NETDFS_H + +#define DFS_GETMANAGERVERSION 0 +#define DFS_ADD 1 +#define DFS_REMOVE 2 +#define DFS_SETINFO 3 +#define DFS_GETINFO 4 +#define DFS_ENUM 5 +#define DFS_RENAME 6 +#define DFS_MOVE 7 +#define DFS_MANAGERGETCONFIGINFO 8 +#define DFS_MANAGERSENDSITEINFO 9 +#define DFS_ADDFTROOT 10 +#define DFS_REMOVEFTROOT 11 +#define DFS_ADDSTDROOT 12 +#define DFS_REMOVESTDROOT 13 +#define DFS_MANAGERINITIALIZE 14 +#define DFS_ADDSTDROOTFORCED 15 +#define DFS_GETDCADDRESS 16 +#define DFS_SETDCADDRESS 17 +#define DFS_FLUSHFTTABLE 18 +#define DFS_ADD2 19 +#define DFS_REMOVE2 20 +#define DFS_ENUMEX 21 +#define DFS_SETINFO2 22 + +typedef struct netdfs_dfs_Info0 { + uint32 dummy; +} NETDFS_DFS_INFO0; + +typedef struct netdfs_dfs_Info1 { + uint32 ptr0_path; + UNISTR2 path; +} NETDFS_DFS_INFO1; + +typedef struct netdfs_dfs_Info2 { + uint32 ptr0_path; + UNISTR2 path; + uint32 ptr0_comment; UNISTR2 comment; uint32 state; - uint32 num_storages; -} DFS_INFO_2; + uint32 num_stores; +} NETDFS_DFS_INFO2; -typedef struct dfs_storage_info { +typedef struct netdfs_dfs_StorageInfo { uint32 state; - uint32 ptr_servername; - UNISTR2 servername; - uint32 ptr_sharename; - UNISTR2 sharename; -} DFS_STORAGE_INFO; - -typedef struct dfs_info_3 { - uint32 ptr_entrypath; - UNISTR2 entrypath; - uint32 ptr_comment; + uint32 ptr0_server; + UNISTR2 server; + uint32 ptr0_share; + UNISTR2 share; +} NETDFS_DFS_STORAGEINFO; + +typedef struct netdfs_dfs_Info3 { + uint32 ptr0_path; + UNISTR2 path; + uint32 ptr0_comment; UNISTR2 comment; uint32 state; - uint32 num_storages; - uint32 ptr_storages; - uint32 num_storage_infos; - DFS_STORAGE_INFO* storages; -} DFS_INFO_3; + uint32 num_stores; + uint32 ptr0_stores; + uint32 size_stores; + NETDFS_DFS_STORAGEINFO *stores; +} NETDFS_DFS_INFO3; + +typedef struct netdfs_dfs_Info4 { + uint32 ptr0_path; + UNISTR2 path; + uint32 ptr0_comment; + UNISTR2 comment; + uint32 state; + uint32 timeout; + struct uuid guid; + uint32 num_stores; + uint32 ptr0_stores; + uint32 size_stores; + NETDFS_DFS_STORAGEINFO *stores; +} NETDFS_DFS_INFO4; + +typedef struct netdfs_dfs_Info100 { + uint32 ptr0_comment; + UNISTR2 comment; +} NETDFS_DFS_INFO100; + +typedef struct netdfs_dfs_Info101 { + uint32 state; +} NETDFS_DFS_INFO101; -typedef struct dfs_info_ctr { +typedef struct netdfs_dfs_Info102 { + uint32 timeout; +} NETDFS_DFS_INFO102; + +typedef struct netdfs_dfs_Info200 { + uint32 ptr0_dom_root; + UNISTR2 dom_root; +} NETDFS_DFS_INFO200; + +typedef struct netdfs_dfs_Info300 { + uint32 flags; + uint32 ptr0_dom_root; + UNISTR2 dom_root; +} NETDFS_DFS_INFO300; + +typedef struct netdfs_dfs_Info_ctr { uint32 switch_value; - uint32 num_entries; - uint32 ptr_dfs_ctr; /* pointer to dfs info union */ - union { - DFS_INFO_1 *info1; - DFS_INFO_2 *info2; - DFS_INFO_3 *info3; - } dfs; -} DFS_INFO_CTR; - -typedef struct dfs_q_dfs_get_info { - UNISTR2 uni_path; - - uint32 ptr_server; - UNISTR2 uni_server; - - uint32 ptr_share; - UNISTR2 uni_share; - - uint32 level; -} DFS_Q_DFS_GET_INFO; + uint32 ptr0; + union netdfs_dfs_Info { + NETDFS_DFS_INFO0 info0; + NETDFS_DFS_INFO1 info1; + NETDFS_DFS_INFO2 info2; + NETDFS_DFS_INFO3 info3; + NETDFS_DFS_INFO4 info4; + NETDFS_DFS_INFO100 info100; + NETDFS_DFS_INFO101 info101; + NETDFS_DFS_INFO102 info102; + } u; +} NETDFS_DFS_INFO_CTR; + +typedef struct netdfs_dfs_EnumArray1 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO1 *s; +} NETDFS_DFS_ENUMARRAY1; + +typedef struct netdfs_dfs_EnumArray2 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO2 *s; +} NETDFS_DFS_ENUMARRAY2; + +typedef struct netdfs_dfs_EnumArray3 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO3 *s; +} NETDFS_DFS_ENUMARRAY3; -typedef struct dfs_r_dfs_get_info { +typedef struct netdfs_dfs_EnumArray4 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO4 *s; +} NETDFS_DFS_ENUMARRAY4; + +typedef struct netdfs_dfs_EnumArray200 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO200 *s; +} NETDFS_DFS_ENUMARRAY200; + +typedef struct netdfs_dfs_EnumArray300 { + uint32 count; + uint32 ptr0_s; + uint32 size_s; + NETDFS_DFS_INFO300 *s; +} NETDFS_DFS_ENUMARRAY300; + +typedef struct netdfs_dfs_EnumInfo_ctr { + uint32 switch_value; + uint32 ptr0; + union netdfs_dfs_EnumInfo { + NETDFS_DFS_ENUMARRAY1 info1; + NETDFS_DFS_ENUMARRAY2 info2; + NETDFS_DFS_ENUMARRAY3 info3; + NETDFS_DFS_ENUMARRAY4 info4; + NETDFS_DFS_ENUMARRAY200 info200; + NETDFS_DFS_ENUMARRAY300 info300; + } u; +} NETDFS_DFS_ENUMINFO_CTR; + +typedef struct netdfs_dfs_EnumStruct { uint32 level; - uint32 ptr_ctr; - DFS_INFO_CTR ctr; + NETDFS_DFS_ENUMINFO_CTR e; +} NETDFS_DFS_ENUMSTRUCT; + +typedef struct netdfs_q_dfs_GetManagerVersion { + uint32 dummy; +} NETDFS_Q_DFS_GETMANAGERVERSION; + +typedef struct netdfs_r_dfs_GetManagerVersion { + uint32 exist_flag; +} NETDFS_R_DFS_GETMANAGERVERSION; + +typedef struct netdfs_q_dfs_Add { + UNISTR2 path; + UNISTR2 server; + uint32 ptr0_share; + UNISTR2 share; + uint32 ptr0_comment; + UNISTR2 comment; + uint32 flags; +} NETDFS_Q_DFS_ADD; + +typedef struct netdfs_r_dfs_Add { + WERROR status; +} NETDFS_R_DFS_ADD; + +typedef struct netdfs_q_dfs_Remove { + UNISTR2 path; + uint32 ptr0_server; + UNISTR2 server; + uint32 ptr0_share; + UNISTR2 share; +} NETDFS_Q_DFS_REMOVE; + +typedef struct netdfs_r_dfs_Remove { WERROR status; -} DFS_R_DFS_GET_INFO; +} NETDFS_R_DFS_REMOVE; -typedef struct dfs_q_dfs_enum { +typedef struct netdfs_q_dfs_SetInfo { + uint32 dummy; +} NETDFS_Q_DFS_SETINFO; + +typedef struct netdfs_r_dfs_SetInfo { + WERROR status; +} NETDFS_R_DFS_SETINFO; + +typedef struct netdfs_q_dfs_GetInfo { + UNISTR2 path; + uint32 ptr0_server; + UNISTR2 server; + uint32 ptr0_share; + UNISTR2 share; uint32 level; - uint32 maxpreflen; - uint32 ptr_buffer; - uint32 level2; - uint32 ptr_num_entries; - uint32 num_entries; - uint32 ptr_num_entries2; - uint32 num_entries2; - ENUM_HND reshnd; -} DFS_Q_DFS_ENUM; - -typedef struct dfs_r_dfs_enum { - DFS_INFO_CTR *ctr; - uint32 ptr_buffer; +} NETDFS_Q_DFS_GETINFO; + +typedef struct netdfs_r_dfs_GetInfo { + NETDFS_DFS_INFO_CTR info; + WERROR status; +} NETDFS_R_DFS_GETINFO; + +typedef struct netdfs_q_dfs_Enum { uint32 level; - uint32 level2; - uint32 ptr_num_entries; - uint32 num_entries; - uint32 ptr_num_entries2; - uint32 num_entries2; - ENUM_HND reshnd; - WERROR status; -} DFS_R_DFS_ENUM; -#endif + uint32 bufsize; + uint32 ptr0_info; + NETDFS_DFS_ENUMSTRUCT info; + uint32 ptr0_unknown; + uint32 unknown; + uint32 ptr0_total; + uint32 total; +} NETDFS_Q_DFS_ENUM; + +typedef struct netdfs_r_dfs_Enum { + uint32 ptr0_info; + NETDFS_DFS_ENUMSTRUCT info; + uint32 ptr0_total; + uint32 total; + WERROR status; +} NETDFS_R_DFS_ENUM; + +typedef struct netdfs_q_dfs_Rename { + uint32 dummy; +} NETDFS_Q_DFS_RENAME; + +typedef struct netdfs_r_dfs_Rename { + WERROR status; +} NETDFS_R_DFS_RENAME; + +typedef struct netdfs_q_dfs_Move { + uint32 dummy; +} NETDFS_Q_DFS_MOVE; + +typedef struct netdfs_r_dfs_Move { + WERROR status; +} NETDFS_R_DFS_MOVE; + +typedef struct netdfs_q_dfs_ManagerGetConfigInfo { + uint32 dummy; +} NETDFS_Q_DFS_MANAGERGETCONFIGINFO; + +typedef struct netdfs_r_dfs_ManagerGetConfigInfo { + WERROR status; +} NETDFS_R_DFS_MANAGERGETCONFIGINFO; + +typedef struct netdfs_q_dfs_ManagerSendSiteInfo { + uint32 dummy; +} NETDFS_Q_DFS_MANAGERSENDSITEINFO; + +typedef struct netdfs_r_dfs_ManagerSendSiteInfo { + WERROR status; +} NETDFS_R_DFS_MANAGERSENDSITEINFO; + +typedef struct netdfs_q_dfs_AddFtRoot { + uint32 dummy; +} NETDFS_Q_DFS_ADDFTROOT; + +typedef struct netdfs_r_dfs_AddFtRoot { + WERROR status; +} NETDFS_R_DFS_ADDFTROOT; + +typedef struct netdfs_q_dfs_RemoveFtRoot { + uint32 dummy; +} NETDFS_Q_DFS_REMOVEFTROOT; + +typedef struct netdfs_r_dfs_RemoveFtRoot { + WERROR status; +} NETDFS_R_DFS_REMOVEFTROOT; + +typedef struct netdfs_q_dfs_AddStdRoot { + uint32 dummy; +} NETDFS_Q_DFS_ADDSTDROOT; + +typedef struct netdfs_r_dfs_AddStdRoot { + WERROR status; +} NETDFS_R_DFS_ADDSTDROOT; + +typedef struct netdfs_q_dfs_RemoveStdRoot { + uint32 dummy; +} NETDFS_Q_DFS_REMOVESTDROOT; + +typedef struct netdfs_r_dfs_RemoveStdRoot { + WERROR status; +} NETDFS_R_DFS_REMOVESTDROOT; + +typedef struct netdfs_q_dfs_ManagerInitialize { + uint32 dummy; +} NETDFS_Q_DFS_MANAGERINITIALIZE; + +typedef struct netdfs_r_dfs_ManagerInitialize { + WERROR status; +} NETDFS_R_DFS_MANAGERINITIALIZE; + +typedef struct netdfs_q_dfs_AddStdRootForced { + uint32 dummy; +} NETDFS_Q_DFS_ADDSTDROOTFORCED; + +typedef struct netdfs_r_dfs_AddStdRootForced { + WERROR status; +} NETDFS_R_DFS_ADDSTDROOTFORCED; + +typedef struct netdfs_q_dfs_GetDcAddress { + uint32 dummy; +} NETDFS_Q_DFS_GETDCADDRESS; + +typedef struct netdfs_r_dfs_GetDcAddress { + WERROR status; +} NETDFS_R_DFS_GETDCADDRESS; + +typedef struct netdfs_q_dfs_SetDcAddress { + uint32 dummy; +} NETDFS_Q_DFS_SETDCADDRESS; + +typedef struct netdfs_r_dfs_SetDcAddress { + WERROR status; +} NETDFS_R_DFS_SETDCADDRESS; + +typedef struct netdfs_q_dfs_FlushFtTable { + uint32 dummy; +} NETDFS_Q_DFS_FLUSHFTTABLE; + +typedef struct netdfs_r_dfs_FlushFtTable { + WERROR status; +} NETDFS_R_DFS_FLUSHFTTABLE; + +typedef struct netdfs_q_dfs_Add2 { + uint32 dummy; +} NETDFS_Q_DFS_ADD2; + +typedef struct netdfs_r_dfs_Add2 { + WERROR status; +} NETDFS_R_DFS_ADD2; + +typedef struct netdfs_q_dfs_Remove2 { + uint32 dummy; +} NETDFS_Q_DFS_REMOVE2; + +typedef struct netdfs_r_dfs_Remove2 { + WERROR status; +} NETDFS_R_DFS_REMOVE2; + +typedef struct netdfs_q_dfs_EnumEx { + uint32 dummy; +} NETDFS_Q_DFS_ENUMEX; + +typedef struct netdfs_r_dfs_EnumEx { + WERROR status; +} NETDFS_R_DFS_ENUMEX; + +typedef struct netdfs_q_dfs_SetInfo2 { + uint32 dummy; +} NETDFS_Q_DFS_SETINFO2; + +typedef struct netdfs_r_dfs_SetInfo2 { + WERROR status; +} NETDFS_R_DFS_SETINFO2; + +#endif /* _RPC_NETDFS_H */ diff --git a/source/include/rpc_lsa.h b/source/include/rpc_lsa.h index dd255c28d5d..c8d6a210b51 100644 --- a/source/include/rpc_lsa.h +++ b/source/include/rpc_lsa.h @@ -80,6 +80,7 @@ #define LSA_UNK_GET_CONNUSER 0x2d /* LsaGetConnectedCredentials ? */ #define LSA_QUERYINFO2 0x2e #define LSA_QUERYTRUSTDOMINFOBYNAME 0x30 +#define LSA_QUERYDOMINFOPOL 0x35 #define LSA_OPENTRUSTDOMBYNAME 0x37 /* XXXX these are here to get a compile! */ @@ -393,7 +394,7 @@ typedef struct lsa_trans_name_info } LSA_TRANS_NAME; /* This number is based on Win2k and later maximum response allowed */ -#define MAX_LOOKUP_SIDS 20480 +#define MAX_LOOKUP_SIDS 20480 /* 0x5000 */ /* LSA_TRANS_NAME_ENUM - LSA Translated Name Enumeration container */ typedef struct lsa_trans_name_enum_info @@ -750,6 +751,25 @@ typedef struct { /*******************************************************/ +/* LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME - LSA Query Open Trusted Domain by Name*/ +typedef struct lsa_q_open_trusted_domain_by_name +{ + POLICY_HND pol; /* policy handle */ + LSA_STRING name; /* domain name */ + uint32 access_mask; /* access mask */ + +} LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME; + +/* LSA_R_OPEN_TRUSTED_DOMAIN_BY_NAME - response to LSA Query Open Trusted Domain by Name */ +typedef struct { + POLICY_HND handle; /* trustdom policy handle */ + NTSTATUS status; /* return code */ +} LSA_R_OPEN_TRUSTED_DOMAIN_BY_NAME; + + +/*******************************************************/ + + typedef struct { POLICY_HND handle; UNISTR4 secretname; @@ -955,4 +975,38 @@ typedef struct r_lsa_query_trusted_domain_info NTSTATUS status; } LSA_R_QUERY_TRUSTED_DOMAIN_INFO; +typedef struct dom_info_kerberos { + uint32 enforce_restrictions; + NTTIME service_tkt_lifetime; + NTTIME user_tkt_lifetime; + NTTIME user_tkt_renewaltime; + NTTIME clock_skew; + NTTIME unknown6; +} LSA_DOM_INFO_POLICY_KERBEROS; + +typedef struct dom_info_efs { + uint32 blob_len; + UNISTR2 efs_blob; +} LSA_DOM_INFO_POLICY_EFS; + +typedef struct lsa_dom_info_union { + uint16 info_class; + LSA_DOM_INFO_POLICY_EFS efs_policy; + LSA_DOM_INFO_POLICY_KERBEROS krb_policy; +} LSA_DOM_INFO_UNION; + +/* LSA_Q_QUERY_DOM_INFO_POLICY - LSA query info */ +typedef struct lsa_q_query_dom_info_policy +{ + POLICY_HND pol; /* policy handle */ + uint16 info_class; /* info class */ +} LSA_Q_QUERY_DOM_INFO_POLICY; + +typedef struct lsa_r_query_dom_info_policy +{ + LSA_DOM_INFO_UNION *info; + NTSTATUS status; +} LSA_R_QUERY_DOM_INFO_POLICY; + + #endif /* _RPC_LSA_H */ diff --git a/source/include/rpc_netlogon.h b/source/include/rpc_netlogon.h index c1d85403448..91f85601e30 100644 --- a/source/include/rpc_netlogon.h +++ b/source/include/rpc_netlogon.h @@ -86,8 +86,17 @@ #define NL_CTRL_REPL_IN_PROGRESS 0x0002 #define NL_CTRL_FULL_SYNC 0x0004 -#define LOGON_EXTRA_SIDS 0x0020 -#define LOGON_RESOURCE_GROUPS 0x0200 +#define LOGON_GUEST 0x00000001 +#define LOGON_NOENCRYPTION 0x00000002 +#define LOGON_CACHED_ACCOUNT 0x00000004 +#define LOGON_USED_LM_PASSWORD 0x00000008 +#define LOGON_EXTRA_SIDS 0x00000020 +#define LOGON_SUBAUTH_SESSION_KEY 0x00000040 +#define LOGON_SERVER_TRUST_ACCOUNT 0x00000080 +#define LOGON_NTLMV2_ENABLED 0x00000100 +#define LOGON_RESOURCE_GROUPS 0x00000200 +#define LOGON_PROFILE_PATH_RETURNED 0x00000400 +#define LOGON_GRACE_LOGON 0x01000000 #define SE_GROUP_MANDATORY 0x00000001 #define SE_GROUP_ENABLED_BY_DEFAULT 0x00000002 diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h index 342db37ea57..2fae514c3d1 100644 --- a/source/include/rpc_samr.h +++ b/source/include/rpc_samr.h @@ -1843,6 +1843,10 @@ typedef struct q_samr_chgpasswd3 } SAMR_Q_CHGPASSWD3; +#define REJECT_REASON_TOO_SHORT 0x00000001 +#define REJECT_REASON_IN_HISTORY 0x00000002 +#define REJECT_REASON_NOT_COMPLEX 0x00000005 + /* SAMR_CHANGE_REJECT */ typedef struct samr_change_reject { diff --git a/source/include/secrets.h b/source/include/secrets.h index f2d1afd96b3..610a14b52be 100644 --- a/source/include/secrets.h +++ b/source/include/secrets.h @@ -75,10 +75,10 @@ typedef struct trusted_dom_pass { * trusted domain entry/entries returned by secrets_get_trusted_domains * (used in _lsa_enum_trust_dom call) */ -typedef struct trustdom { - smb_ucs2_t *name; +struct trustdom_info { + char *name; DOM_SID sid; -} TRUSTDOM; +}; /* * Format of an OpenAFS keyfile diff --git a/source/include/smb.h b/source/include/smb.h index 3a6f68b9ecc..b167e4ee126 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -224,18 +224,26 @@ typedef struct nttime_info { /* Allowable account control bits */ -#define ACB_DISABLED 0x0001 /* 1 = User account disabled */ -#define ACB_HOMDIRREQ 0x0002 /* 1 = Home directory required */ -#define ACB_PWNOTREQ 0x0004 /* 1 = User password not required */ -#define ACB_TEMPDUP 0x0008 /* 1 = Temporary duplicate account */ -#define ACB_NORMAL 0x0010 /* 1 = Normal user account */ -#define ACB_MNS 0x0020 /* 1 = MNS logon user account */ -#define ACB_DOMTRUST 0x0040 /* 1 = Interdomain trust account */ -#define ACB_WSTRUST 0x0080 /* 1 = Workstation trust account */ -#define ACB_SVRTRUST 0x0100 /* 1 = Server trust account (BDC) */ -#define ACB_PWNOEXP 0x0200 /* 1 = User password does not expire */ -#define ACB_AUTOLOCK 0x0400 /* 1 = Account auto locked */ - +#define ACB_DISABLED 0x00000001 /* 1 = User account disabled */ +#define ACB_HOMDIRREQ 0x00000002 /* 1 = Home directory required */ +#define ACB_PWNOTREQ 0x00000004 /* 1 = User password not required */ +#define ACB_TEMPDUP 0x00000008 /* 1 = Temporary duplicate account */ +#define ACB_NORMAL 0x00000010 /* 1 = Normal user account */ +#define ACB_MNS 0x00000020 /* 1 = MNS logon user account */ +#define ACB_DOMTRUST 0x00000040 /* 1 = Interdomain trust account */ +#define ACB_WSTRUST 0x00000080 /* 1 = Workstation trust account */ +#define ACB_SVRTRUST 0x00000100 /* 1 = Server trust account (BDC) */ +#define ACB_PWNOEXP 0x00000200 /* 1 = User password does not expire */ +#define ACB_AUTOLOCK 0x00000400 /* 1 = Account auto locked */ + +/* only valid for > Windows 2000 */ +#define ACB_ENC_TXT_PWD_ALLOWED 0x00000800 /* 1 = Text password encryped */ +#define ACB_SMARTCARD_REQUIRED 0x00001000 /* 1 = Smart Card required */ +#define ACB_TRUSTED_FOR_DELEGATION 0x00002000 /* 1 = Trusted for Delegation */ +#define ACB_NOT_DELEGATED 0x00004000 /* 1 = Not delegated */ +#define ACB_USE_DES_KEY_ONLY 0x00008000 /* 1 = Use DES key only */ +#define ACB_DONT_REQUIRE_PREAUTH 0x00010000 /* 1 = Preauth not required */ + #define MAX_HOURS_LEN 32 #ifndef MAXSUBAUTHS @@ -262,6 +270,9 @@ enum SID_NAME_USE { #define LOOKUP_NAME_REMOTE 2 /* Ask others */ #define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED|LOOKUP_NAME_REMOTE) +#define LOOKUP_NAME_GROUP 4 /* This is a NASTY hack for valid users = @foo + * where foo also exists in as user. */ + /** * @brief Security Identifier * @@ -280,6 +291,21 @@ typedef struct sid_info { uint32 sub_auths[MAXSUBAUTHS]; } DOM_SID; +struct lsa_dom_info { + BOOL valid; + DOM_SID sid; + const char *name; + int num_idxs; + int *idxs; +}; + +struct lsa_name_info { + uint32 rid; + enum SID_NAME_USE type; + const char *name; + int dom_idx; +}; + /* Some well-known SIDs */ extern const DOM_SID global_sid_World_Domain; extern const DOM_SID global_sid_World; @@ -302,6 +328,8 @@ extern const DOM_SID global_sid_Builtin_Server_Operators; extern const DOM_SID global_sid_Builtin_Print_Operators; extern const DOM_SID global_sid_Builtin_Backup_Operators; extern const DOM_SID global_sid_Builtin_Replicator; +extern const DOM_SID global_sid_Unix_Users; +extern const DOM_SID global_sid_Unix_Groups; /* * The complete list of SIDS belonging to this user. @@ -316,7 +344,7 @@ extern const DOM_SID global_sid_Builtin_Replicator; #define PRIMARY_USER_SID_INDEX 0 #define PRIMARY_GROUP_SID_INDEX 1 -typedef struct _nt_user_token { +typedef struct nt_user_token { size_t num_sids; DOM_SID *user_sids; SE_PRIV privileges; @@ -1719,6 +1747,22 @@ typedef struct uuid_flat { /* map readonly options */ enum mapreadonly_options {MAP_READONLY_NO, MAP_READONLY_YES, MAP_READONLY_PERMISSIONS}; +/* usershare error codes. */ +enum usershare_err { + USERSHARE_OK=0, + USERSHARE_MALFORMED_FILE, + USERSHARE_BAD_VERSION, + USERSHARE_MALFORMED_PATH, + USERSHARE_MALFORMED_COMMENT_DEF, + USERSHARE_MALFORMED_ACL_DEF, + USERSHARE_ACL_ERR, + USERSHARE_PATH_NOT_ABSOLUTE, + USERSHARE_PATH_IS_DENIED, + USERSHARE_PATH_NOT_ALLOWED, + USERSHARE_PATH_NOT_DIRECTORY, + USERSHARE_POSIX_ERR +}; + /* Different reasons for closing a file. */ enum file_close_type {NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE}; diff --git a/source/include/smbldap.h b/source/include/smbldap.h index bea1a6d84a3..8870205bbbc 100644 --- a/source/include/smbldap.h +++ b/source/include/smbldap.h @@ -131,8 +131,7 @@ NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct smbldap_state **smbldap_state); const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ); -const char** get_attr_list( ATTRIB_MAP_ENTRY table[] ); -void free_attr_list( const char **list ); +const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] ); void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value); void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing, LDAPMod ***mods, @@ -207,7 +206,17 @@ int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state, NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location); -const char** get_userattr_list( int schema_ver ); +const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver ); + +char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, + const char *attribute, + TALLOC_CTX *mem_ctx); +void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result); +void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod); +const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, + LDAPMessage *entry); + + #endif /* HAVE_LDAP */ diff --git a/source/intl/lang_tdb.c b/source/intl/lang_tdb.c index d3422f0d78a..d20a15d90e2 100644 --- a/source/intl/lang_tdb.c +++ b/source/intl/lang_tdb.c @@ -34,7 +34,7 @@ static BOOL load_msg(const char *msg_file) char *msgid, *msgstr; TDB_DATA key, data; - lines = file_lines_load(msg_file, &num_lines); + lines = file_lines_load(msg_file, &num_lines,0); if (!lines) { return False; diff --git a/source/lib/dummysmbd.c b/source/lib/dummysmbd.c index 1b31dff4995..9b587224e3e 100644 --- a/source/lib/dummysmbd.c +++ b/source/lib/dummysmbd.c @@ -29,3 +29,12 @@ void decrement_smbd_process_count( void ) return; } +int find_service(fstring service) +{ + return -1; +} + +BOOL conn_snum_used(int snum) +{ + return False; +} diff --git a/source/lib/events.c b/source/lib/events.c new file mode 100644 index 00000000000..314f0749794 --- /dev/null +++ b/source/lib/events.c @@ -0,0 +1,125 @@ +/* + Unix SMB/CIFS implementation. + Timed event library. + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Volker Lendecke 2005 + + 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" + +static struct timed_event *timed_events; + +static int timed_event_destructor(void *p) +{ + struct timed_event *te = talloc_get_type_abort(p, struct timed_event); + DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te, + te->event_name)); + DLIST_REMOVE(timed_events, te); + return 0; +} + +/**************************************************************************** + Schedule a function for future calling, cancel with talloc_free(). + It's the responsibility of the handler to call talloc_free() on the event + handed to it. +****************************************************************************/ + +struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, + struct timeval when, + const char *event_name, + void (*handler)(struct timed_event *te, + const struct timeval *now, + void *private_data), + void *private_data) +{ + struct timed_event *te, *last_te, *cur_te; + + te = TALLOC_P(mem_ctx, struct timed_event); + if (te == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + te->when = when; + te->event_name = event_name; + te->handler = handler; + te->private_data = private_data; + + /* keep the list ordered */ + last_te = NULL; + for (cur_te = timed_events; cur_te; cur_te = cur_te->next) { + /* if the new event comes before the current one break */ + if (!timeval_is_zero(&cur_te->when) && + timeval_compare(&te->when, &cur_te->when) < 0) { + break; + } + last_te = cur_te; + } + + DLIST_ADD_AFTER(timed_events, te, last_te); + talloc_set_destructor(te, timed_event_destructor); + + DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name, + (unsigned long)te)); + return te; +} + +void run_events(void) +{ + struct timeval now; + + if (timed_events == NULL) { + /* No syscall if there are no events */ + DEBUG(10, ("run_events: No events\n")); + return; + } + + GetTimeOfDay(&now); + + if (timeval_compare(&now, &timed_events->when) < 0) { + /* Nothing to do yet */ + DEBUG(10, ("run_events: Nothing to do\n")); + return; + } + + DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name, + (unsigned long)timed_events)); + + timed_events->handler(timed_events, &now, timed_events->private_data); + return; +} + +struct timeval *get_timed_events_timeout(struct timeval *to_ret, time_t default_to) +{ + struct timeval now; + + if (timed_events == NULL) { + if (default_to == (time_t)-1) { + return NULL; + } + *to_ret = timeval_set(default_to, 0); + return to_ret; + } + + now = timeval_current(); + *to_ret = timeval_until(&now, &timed_events->when); + + DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec, + (int)to_ret->tv_usec)); + + return to_ret; +} diff --git a/source/lib/genrand.c b/source/lib/genrand.c index f37bbc9c2fd..5b643bf297e 100644 --- a/source/lib/genrand.c +++ b/source/lib/genrand.c @@ -114,14 +114,14 @@ static int do_reseed(BOOL use_fd, int fd) * seriously this will be secret. */ - pw = getpwnam_alloc("root"); + pw = getpwnam_alloc(NULL, "root"); if (pw && pw->pw_passwd) { size_t i; unsigned char md4_tmp[16]; mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd)); for (i=0;i<16;i++) seed_inbuf[8+i] ^= md4_tmp[i]; - passwd_free(&pw); + talloc_free(pw); } /* diff --git a/source/lib/messages.c b/source/lib/messages.c index 058bbc99b0b..2d6518aed6a 100644 --- a/source/lib/messages.c +++ b/source/lib/messages.c @@ -604,4 +604,19 @@ BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type, *n_sent = msg_all.n_sent; return True; } + +/* + * Block and unblock receiving of messages. Allows removal of race conditions + * when doing a fork and changing message disposition. + */ + +void message_block(void) +{ + BlockSignals(True, SIGUSR1); +} + +void message_unblock(void) +{ + BlockSignals(False, SIGUSR1); +} /** @} **/ diff --git a/source/lib/pam_errors.c b/source/lib/pam_errors.c index 212d3831fd5..8a4c41d7df5 100644 --- a/source/lib/pam_errors.c +++ b/source/lib/pam_errors.c @@ -71,6 +71,7 @@ static const struct { {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD}, {NT_STATUS_ACCOUNT_LOCKED_OUT, PAM_MAXTRIES}, {NT_STATUS_NO_MEMORY, PAM_BUF_ERR}, + {NT_STATUS_PASSWORD_RESTRICTION, PAM_PERM_DENIED}, {NT_STATUS_OK, PAM_SUCCESS} }; diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c index b041eb7f1b2..08e41083b59 100644 --- a/source/lib/pidfile.c +++ b/source/lib/pidfile.c @@ -32,7 +32,8 @@ pid_t pidfile_pid(const char *name) { int fd; char pidstr[20]; - unsigned ret; + pid_t pid; + unsigned int ret; pstring pidFile; slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_piddir(), name); @@ -57,7 +58,8 @@ pid_t pidfile_pid(const char *name) goto noproc; } - if (!process_exists_by_pid(ret)) { + pid = (pid_t)ret; + if (!process_exists_by_pid(pid)) { goto noproc; } diff --git a/source/lib/readline.c b/source/lib/readline.c index 78b99fd7fb0..c1f1dc7f400 100644 --- a/source/lib/readline.c +++ b/source/lib/readline.c @@ -50,7 +50,7 @@ Display the prompt and wait for input. Call callback() regularly ****************************************************************************/ -static char *smb_readline_replacement(char *prompt, void (*callback)(void), +static char *smb_readline_replacement(const char *prompt, void (*callback)(void), char **(completion_fn)(const char *text, int start, int end)) { fd_set fds; @@ -82,7 +82,7 @@ static char *smb_readline_replacement(char *prompt, void (*callback)(void), Display the prompt and wait for input. Call callback() regularly. ****************************************************************************/ -char *smb_readline(char *prompt, void (*callback)(void), +char *smb_readline(const char *prompt, void (*callback)(void), char **(completion_fn)(const char *text, int start, int end)) { #if HAVE_LIBREADLINE diff --git a/source/lib/secdesc.c b/source/lib/secdesc.c index ace0aee8664..273bf0f0a3f 100644 --- a/source/lib/secdesc.c +++ b/source/lib/secdesc.c @@ -23,6 +23,15 @@ #include "includes.h" +/* Map generic permissions to file object specific permissions */ + +struct generic_mapping file_generic_mapping = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_GENERIC_ALL +}; + /******************************************************************* Works out the linearization size of a SEC_DESC. ********************************************************************/ @@ -520,3 +529,4 @@ void init_sec_access(SEC_ACCESS *t, uint32 mask) t->mask = mask; } + diff --git a/source/lib/sharesec.c b/source/lib/sharesec.c new file mode 100644 index 00000000000..b98e304582a --- /dev/null +++ b/source/lib/sharesec.c @@ -0,0 +1,308 @@ +/* + * Unix SMB/Netbios implementation. + * SEC_DESC handling functions + * Copyright (C) Jeremy R. Allison 1995-2003. + * + * 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" + +/******************************************************************* + Create the share security tdb. + ********************************************************************/ + +static TDB_CONTEXT *share_tdb; /* used for share security descriptors */ +#define SHARE_DATABASE_VERSION_V1 1 +#define SHARE_DATABASE_VERSION_V2 2 /* version id in little endian. */ + +/* Map generic permissions to file object specific permissions */ + +static struct generic_mapping file_generic_mapping = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_GENERIC_ALL +}; + + +BOOL share_info_db_init(void) +{ + const char *vstring = "INFO/version"; + int32 vers_id; + + if (share_tdb) { + return True; + } + + share_tdb = tdb_open_log(lock_path("share_info.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + if (!share_tdb) { + DEBUG(0,("Failed to open share info database %s (%s)\n", + lock_path("share_info.tdb"), strerror(errno) )); + return False; + } + + /* handle a Samba upgrade */ + tdb_lock_bystring(share_tdb, vstring, 0); + + /* Cope with byte-reversed older versions of the db. */ + vers_id = tdb_fetch_int32(share_tdb, vstring); + if ((vers_id == SHARE_DATABASE_VERSION_V1) || (IREV(vers_id) == SHARE_DATABASE_VERSION_V1)) { + /* Written on a bigendian machine with old fetch_int code. Save as le. */ + tdb_store_int32(share_tdb, vstring, SHARE_DATABASE_VERSION_V2); + vers_id = SHARE_DATABASE_VERSION_V2; + } + + if (vers_id != SHARE_DATABASE_VERSION_V2) { + tdb_traverse(share_tdb, tdb_traverse_delete_fn, NULL); + tdb_store_int32(share_tdb, vstring, SHARE_DATABASE_VERSION_V2); + } + tdb_unlock_bystring(share_tdb, vstring); + + return True; +} + +/******************************************************************* + Fake up a Everyone, default access as a default. + def_access is a GENERIC_XXX access mode. + ********************************************************************/ + +SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, size_t *psize, uint32 def_access) +{ + SEC_ACCESS sa; + SEC_ACE ace; + SEC_ACL *psa = NULL; + SEC_DESC *psd = NULL; + uint32 spec_access = def_access; + + se_map_generic(&spec_access, &file_generic_mapping); + + init_sec_access(&sa, def_access | spec_access ); + init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0); + + if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &ace)) != NULL) { + psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, psize); + } + + if (!psd) { + DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n")); + return NULL; + } + + return psd; +} + +/******************************************************************* + Pull a security descriptor from the share tdb. + ********************************************************************/ + +SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize) +{ + prs_struct ps; + fstring key; + SEC_DESC *psd = NULL; + + if (!share_info_db_init()) { + return NULL; + } + + *psize = 0; + + /* Fetch security descriptor from tdb */ + + slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum)); + + if (tdb_prs_fetch(share_tdb, key, &ps, ctx)!=0 || + !sec_io_desc("get_share_security", &psd, &ps, 1)) { + + DEBUG(4,("get_share_security: using default secdesc for %s\n", lp_servicename(snum) )); + + return get_share_security_default(ctx, psize, GENERIC_ALL_ACCESS); + } + + if (psd) + *psize = sec_desc_size(psd); + + prs_mem_free(&ps); + return psd; +} + +/******************************************************************* + Store a security descriptor in the share db. + ********************************************************************/ + +BOOL set_share_security(TALLOC_CTX *ctx, const char *share_name, SEC_DESC *psd) +{ + prs_struct ps; + TALLOC_CTX *mem_ctx = NULL; + fstring key; + BOOL ret = False; + + if (!share_info_db_init()) { + return False; + } + + mem_ctx = talloc_init("set_share_security"); + if (mem_ctx == NULL) + return False; + + prs_init(&ps, (uint32)sec_desc_size(psd), mem_ctx, MARSHALL); + + if (!sec_io_desc("share_security", &psd, &ps, 1)) + goto out; + + slprintf(key, sizeof(key)-1, "SECDESC/%s", share_name); + + if (tdb_prs_store(share_tdb, key, &ps)==0) { + ret = True; + DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name )); + } else { + DEBUG(1,("set_share_security: Failed to store secdesc for %s\n", share_name )); + } + + /* Free malloc'ed memory */ + +out: + + prs_mem_free(&ps); + if (mem_ctx) + talloc_destroy(mem_ctx); + return ret; +} + +/******************************************************************* + Delete a security descriptor. +********************************************************************/ + +BOOL delete_share_security(int snum) +{ + TDB_DATA kbuf; + fstring key; + + slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum)); + kbuf.dptr = key; + kbuf.dsize = strlen(key)+1; + + if (tdb_delete(share_tdb, kbuf) != 0) { + DEBUG(0,("delete_share_security: Failed to delete entry for share %s\n", + lp_servicename(snum) )); + return False; + } + + return True; +} + +/*************************************************************************** + Parse the contents of an acl string from a usershare file. +***************************************************************************/ + +BOOL parse_usershare_acl(TALLOC_CTX *ctx, const char *acl_str, SEC_DESC **ppsd) +{ + size_t s_size = 0; + const char *pacl = acl_str; + int num_aces = 0; + SEC_ACE *ace_list = NULL; + SEC_ACL *psa = NULL; + SEC_DESC *psd = NULL; + size_t sd_size = 0; + int i; + + *ppsd = NULL; + + /* If the acl string is blank return "Everyone:R" */ + if (!*acl_str) { + SEC_DESC *default_psd = get_share_security_default(ctx, &s_size, GENERIC_READ_ACCESS); + if (!default_psd) { + return False; + } + *ppsd = default_psd; + return True; + } + + num_aces = 1; + + /* Add the number of ',' characters to get the number of aces. */ + num_aces += count_chars(pacl,','); + + ace_list = TALLOC_ARRAY(ctx, SEC_ACE, num_aces); + if (!ace_list) { + return False; + } + + for (i = 0; i < num_aces; i++) { + SEC_ACCESS sa; + uint32 g_access; + uint32 s_access; + DOM_SID sid; + fstring sidstr; + uint8 type = SEC_ACE_TYPE_ACCESS_ALLOWED; + + if (!next_token(&pacl, sidstr, ":", sizeof(sidstr))) { + DEBUG(0,("parse_usershare_acl: malformed usershare acl looking " + "for ':' in string '%s'\n", pacl)); + return False; + } + + if (!string_to_sid(&sid, sidstr)) { + DEBUG(0,("parse_usershare_acl: failed to convert %s to sid.\n", + sidstr )); + return False; + } + + switch (*pacl) { + case 'F': /* Full Control, ie. R+W */ + case 'f': /* Full Control, ie. R+W */ + s_access = g_access = GENERIC_ALL_ACCESS; + break; + case 'R': /* Read only. */ + case 'r': /* Read only. */ + s_access = g_access = GENERIC_READ_ACCESS; + break; + case 'D': /* Deny all to this SID. */ + case 'd': /* Deny all to this SID. */ + type = SEC_ACE_TYPE_ACCESS_DENIED; + s_access = g_access = GENERIC_ALL_ACCESS; + break; + default: + DEBUG(0,("parse_usershare_acl: unknown acl type at %s.\n", + pacl )); + return False; + } + + pacl++; + if (*pacl && *pacl != ',') { + DEBUG(0,("parse_usershare_acl: bad acl string at %s.\n", + pacl )); + return False; + } + pacl++; /* Go past any ',' */ + + se_map_generic(&s_access, &file_generic_mapping); + init_sec_access(&sa, g_access | s_access ); + init_sec_ace(&ace_list[i], &sid, type, sa, 0); + } + + if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, num_aces, ace_list)) != NULL) { + psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, &sd_size); + } + + if (!psd) { + DEBUG(0,("parse_usershare_acl: Failed to make SEC_DESC.\n")); + return False; + } + + *ppsd = psd; + return True; +} diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c index 609816b8774..c045be51c5f 100644 --- a/source/lib/smbldap.c +++ b/source/lib/smbldap.c @@ -230,7 +230,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { Return the list of attribute names from a mapping table **********************************************************************/ - const char** get_attr_list( ATTRIB_MAP_ENTRY table[] ) + const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] ) { const char **names; int i = 0; @@ -239,7 +239,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { i++; i++; - names = SMB_MALLOC_ARRAY( const char*, i ); + names = TALLOC_ARRAY( mem_ctx, const char*, i ); if ( !names ) { DEBUG(0,("get_attr_list: out of memory\n")); return NULL; @@ -247,7 +247,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { i = 0; while ( table[i].attrib != LDAP_ATTR_LIST_END ) { - names[i] = SMB_STRDUP( table[i].name ); + names[i] = talloc_strdup( names, table[i].name ); i++; } names[i] = NULL; @@ -255,29 +255,6 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return names; } -/********************************************************************* - Cleanup - ********************************************************************/ - - void free_attr_list( const char **list ) -{ - int i = 0; - - if ( !list ) - return; - - while ( list[i] ) { - /* SAFE_FREE generates a warning here that can't be gotten rid - * of with CONST_DISCARD */ - if (list[i] != NULL) { - free(CONST_DISCARD(char *, list[i])); - } - i+=1; - } - - SAFE_FREE( list ); -} - /******************************************************************* Search an attribute and return the first value found. ******************************************************************/ @@ -321,6 +298,88 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { sizeof(pstring)); } + char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, + const char *attribute, + TALLOC_CTX *mem_ctx) +{ + char **values; + char *result; + + if (attribute == NULL) { + return NULL; + } + + values = ldap_get_values(ldap_struct, entry, attribute); + + if (values == NULL) { + DEBUG(10, ("attribute %s does not exist\n", attribute)); + return NULL; + } + + if (ldap_count_values(values) != 1) { + DEBUG(10, ("attribute %s has %d values, expected only one\n", + attribute, ldap_count_values(values))); + ldap_value_free(values); + return NULL; + } + + if (pull_utf8_talloc(mem_ctx, &result, values[0]) < 0) { + DEBUG(10, ("pull_utf8_talloc failed\n")); + ldap_value_free(values); + return NULL; + } + + ldap_value_free(values); + +#ifdef DEBUG_PASSWORDS + DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", + attribute, result)); +#endif + return result; +} + + static int ldapmsg_destructor(void *p) { + LDAPMessage **result = talloc_get_type_abort(p, LDAPMessage *); + ldap_msgfree(*result); + return 0; +} + + void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result) +{ + LDAPMessage **handle; + + if (result == NULL) { + return; + } + + handle = TALLOC_P(mem_ctx, LDAPMessage *); + SMB_ASSERT(handle != NULL); + + *handle = result; + talloc_set_destructor(handle, ldapmsg_destructor); +} + + static int ldapmod_destructor(void *p) { + LDAPMod ***result = talloc_get_type_abort(p, LDAPMod **); + ldap_mods_free(*result, True); + return 0; +} + + void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod) +{ + LDAPMod ***handle; + + if (mod == NULL) { + return; + } + + handle = TALLOC_P(mem_ctx, LDAPMod **); + SMB_ASSERT(handle != NULL); + + *handle = mod; + talloc_set_destructor(handle, ldapmod_destructor); +} + /************************************************************************ Routine to manage the LDAPMod structure array manage memory used by the array, by each struct, and values @@ -1041,6 +1100,14 @@ static int another_ldap_try(struct smbldap_state *ldap_state, int *rc, return True; } + if (open_rc == LDAP_INSUFFICIENT_ACCESS) { + /* The fact that we are non-root or any other + * access-denied condition will not change in the next + * round of trying */ + *rc = open_rc; + break; + } + if (got_alarm) { *rc = LDAP_TIMEOUT; break; @@ -1123,12 +1190,22 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, alarm(lp_ldap_timeout()); /* End setup timeout. */ - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope, utf8_filter, CONST_DISCARD(char **, attrs), attrsonly, sctrls, cctrls, &timeout, sizelimit, res); + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("Failed search for base: %s, error: %s " + "(%s)\n", base, ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + } + } SAFE_FREE(utf8_filter); @@ -1257,8 +1334,18 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs); + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("Failed to modify dn: %s, error: %s " + "(%s)\n", dn, ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + } + } SAFE_FREE(utf8_dn); return rc; @@ -1279,8 +1366,18 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs); + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("Failed to add dn: %s, error: %s " + "(%s)\n", dn, ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + } + } SAFE_FREE(utf8_dn); return rc; @@ -1301,8 +1398,18 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn); + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("Failed to delete dn: %s, error: %s " + "(%s)\n", dn, ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + } + } SAFE_FREE(utf8_dn); return rc; @@ -1320,34 +1427,33 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state, if (!ldap_state) return (-1); - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap); + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("Extended operation failed with error: %s " + "(%s)\n", ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + } + } + return rc; } /******************************************************************* run the search by name. ******************************************************************/ -int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter, - const char **search_attr, LDAPMessage ** result) +int smbldap_search_suffix (struct smbldap_state *ldap_state, + const char *filter, const char **search_attr, + LDAPMessage ** result) { - int scope = LDAP_SCOPE_SUBTREE; - int rc; - - rc = smbldap_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0,("smbldap_search_suffix: Problem during the LDAP search: %s (%s)\n", - ld_error?ld_error:"(unknown)", ldap_err2string (rc))); - SAFE_FREE(ld_error); - } - - return rc; + return smbldap_search(ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, + filter, search_attr, 0, result); } static void smbldap_idle_fn(void **data, time_t *interval, time_t now) @@ -1442,6 +1548,25 @@ char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry) return unix_dn; } + const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, + LDAPMessage *entry) +{ + char *utf8_dn, *unix_dn; + + utf8_dn = ldap_get_dn(ld, entry); + if (!utf8_dn) { + DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n")); + return NULL; + } + if (pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn) == (size_t)-1) { + DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 " + "[%s]\n", utf8_dn)); + return NULL; + } + ldap_memfree(utf8_dn); + return unix_dn; +} + /******************************************************************* Check if root-dse has a certain Control or Extension ********************************************************************/ diff --git a/source/lib/smbldap_util.c b/source/lib/smbldap_util.c index 4679b864874..7b4cf4d079f 100644 --- a/source/lib/smbldap_util.c +++ b/source/lib/smbldap_util.c @@ -99,21 +99,17 @@ static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, pstring filter, dn; LDAPMod **mods = NULL; int rc; - int ldap_op; LDAPMessage *result = NULL; int num_result; const char **attr_list; - uid_t u_low, u_high; - gid_t g_low, g_high; - uint32 rid_low, rid_high; slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), domain_name, LDAP_OBJ_DOMINFO); - attr_list = get_attr_list( dominfo_attr_list ); + attr_list = get_attr_list( NULL, dominfo_attr_list ); rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; @@ -122,80 +118,72 @@ static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, num_result = ldap_count_entries(ldap_state->ldap_struct, result); if (num_result > 1) { - DEBUG (0, ("More than domain with that name exists: bailing out!\n")); + DEBUG (0, ("More than domain with that name exists: bailing " + "out!\n")); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } /* Check if we need to add an entry */ DEBUG(3,("Adding new domain\n")); - ldap_op = LDAP_MOD_ADD; - pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name, lp_ldap_suffix()); + pstr_sprintf(dn, "%s=%s,%s", + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), + domain_name, lp_ldap_suffix()); /* Free original search */ ldap_msgfree(result); - /* make the changes - the entry *must* not already have samba attributes */ - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name); + /* make the changes - the entry *must* not already have samba + * attributes */ - /* If we don't have an entry, then ask secrets.tdb for what it thinks. + smbldap_set_mod(&mods, LDAP_MOD_ADD, + get_attr_key2string(dominfo_attr_list, + LDAP_ATTR_DOMAIN), + domain_name); + + /* If we don't have an entry, then ask secrets.tdb for what it thinks. It may choose to make it up */ sid_to_string(sid_string, get_global_sam_sid()); - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string); - - slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base()); - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), + smbldap_set_mod(&mods, LDAP_MOD_ADD, + get_attr_key2string(dominfo_attr_list, + LDAP_ATTR_DOM_SID), + sid_string); + + slprintf(algorithmic_rid_base_string, + sizeof(algorithmic_rid_base_string) - 1, "%i", + algorithmic_rid_base()); + smbldap_set_mod(&mods, LDAP_MOD_ADD, + get_attr_key2string(dominfo_attr_list, + LDAP_ATTR_ALGORITHMIC_RID_BASE), algorithmic_rid_base_string); smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO); - /* add the sambaNext[User|Group]Rid attributes if the idmap ranges are set. - TODO: fix all the places where the line between idmap and normal operations - needed by smbd gets fuzzy --jerry 2003-08-11 */ + /* add the sambaNextUserRid attributes. */ - if ( lp_idmap_uid(&u_low, &u_high) && lp_idmap_gid(&g_low, &g_high) - && get_free_rid_range(&rid_low, &rid_high) ) { + uint32 rid = BASE_RID; fstring rid_str; - fstr_sprintf( rid_str, "%i", rid_high|USER_RID_TYPE ); + fstr_sprintf( rid_str, "%i", rid ); DEBUG(10,("setting next available user rid [%s]\n", rid_str)); smbldap_set_mod(&mods, LDAP_MOD_ADD, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), - rid_str); - - fstr_sprintf( rid_str, "%i", rid_high|GROUP_RID_TYPE ); - DEBUG(10,("setting next available group rid [%s]\n", rid_str)); - smbldap_set_mod(&mods, LDAP_MOD_ADD, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), + get_attr_key2string(dominfo_attr_list, + LDAP_ATTR_NEXT_USERRID), rid_str); - } - switch(ldap_op) - { - case LDAP_MOD_ADD: - rc = smbldap_add(ldap_state, dn, mods); - break; - case LDAP_MOD_REPLACE: - rc = smbldap_modify(ldap_state, dn, mods); - break; - default: - DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op)); - return NT_STATUS_INVALID_PARAMETER; - } - + rc = smbldap_add(ldap_state, dn, mods); + if (rc!=LDAP_SUCCESS) { char *ld_error = NULL; - ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n", - ldap_op == LDAP_MOD_ADD ? "add" : "modify", - dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(1,("failed to add domain dn= %s with: %s\n\t%s\n", + dn, ldap_err2string(rc), + ld_error?ld_error:"unknown")); SAFE_FREE(ld_error); ldap_mods_free(mods, True); @@ -227,9 +215,9 @@ NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state, DEBUG(2, ("Searching for:[%s]\n", filter)); - attr_list = get_attr_list( dominfo_attr_list ); + attr_list = get_attr_list( NULL, dominfo_attr_list ); rc = smbldap_search_suffix(ldap_state, filter, attr_list , result); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc))); diff --git a/source/lib/system_smbd.c b/source/lib/system_smbd.c index 6c65f61ad7a..1d4f88fbb96 100644 --- a/source/lib/system_smbd.c +++ b/source/lib/system_smbd.c @@ -28,47 +28,6 @@ #ifndef HAVE_GETGROUPLIST -static int int_compare( int *a, int *b ) -{ - if ( *a == *b ) - return 0; - else if ( *a < *b ) - return -1; - else - return 1; -} - -void remove_duplicate_gids( int *num_groups, gid_t *groups ) -{ - int i; - int count = *num_groups; - - if ( *num_groups <= 0 || !groups ) - return; - - DEBUG(8,("remove_duplicate_gids: Enter %d gids\n", *num_groups)); - - qsort( groups, *num_groups, sizeof(gid_t), QSORT_CAST int_compare ); - - for ( i=1; i= 10 ) { - DEBUG(10,("user_in_winbind_group_list: using groups -- ")); + DEBUG(10,("user_in_winbind_group: using groups -- ")); for ( i=0; ipw_gid))) { - DEBUG(10,("user_in_unix_group_list: group %s is " + DEBUG(10,("user_in_unix_group: group %s is " "primary group.\n", gname )); return True; } @@ -501,13 +507,13 @@ BOOL user_in_unix_group_list(const char *user,const char *gname) user_list = get_users_in_group(gname); if (user_list == NULL) { - DEBUG(10,("user_in_unix_group_list: no such group %s\n", + DEBUG(10,("user_in_unix_group: no such group %s\n", gname )); return False; } for (member = user_list; member; member = member->next) { - DEBUG(10,("user_in_unix_group_list: checking user %s against " + DEBUG(10,("user_in_unix_group: checking user %s against " "member %s\n", user, member->unix_name )); if (strequal(member->unix_name,user)) { free_userlist(user_list); @@ -523,35 +529,17 @@ BOOL user_in_unix_group_list(const char *user,const char *gname) Check if a user is in a group list. Ask winbind first, then use UNIX. ****************************************************************************/ -BOOL user_in_group_list(const char *user, const char *gname, gid_t *groups, - size_t n_groups) +BOOL user_in_group(const char *user, const char *gname) { BOOL winbind_answered = False; BOOL ret; - gid_t gid; - unsigned i; - gid = nametogid(gname); - if (gid == (gid_t)-1) - return False; - - if (groups && n_groups > 0) { - for (i=0; i < n_groups; i++) { - if (groups[i] == gid) { - return True; - } - } - return False; - } - - /* fallback if we don't yet have the group list */ - - ret = user_in_winbind_group_list(user, gname, &winbind_answered); + ret = user_in_winbind_group(user, gname, &winbind_answered); if (!winbind_answered) - ret = user_in_unix_group_list(user, gname); + ret = user_in_unix_group(user, gname); if (ret) - DEBUG(10,("user_in_group_list: user |%s| is in group |%s|\n", + DEBUG(10,("user_in_group: user |%s| is in group |%s|\n", user, gname)); return ret; } @@ -561,8 +549,7 @@ BOOL user_in_group_list(const char *user, const char *gname, gid_t *groups, and netgroup lists. ****************************************************************************/ -BOOL user_in_list(const char *user,const char **list, gid_t *groups, - size_t n_groups) +BOOL user_in_list(const char *user,const char **list) { if (!list || !*list) return False; @@ -590,10 +577,9 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, * Old behaviour. Check netgroup list * followed by UNIX list. */ - if(user_in_netgroup_list(user, *list +1)) + if(user_in_netgroup(user, *list +1)) return True; - if(user_in_group_list(user, *list +1, groups, - n_groups)) + if(user_in_group(user, *list +1)) return True; } else if (**list == '+') { @@ -601,10 +587,9 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, /* * Search UNIX list followed by netgroup. */ - if(user_in_group_list(user, *list +2, groups, - n_groups)) + if(user_in_group(user, *list +2)) return True; - if(user_in_netgroup_list(user, *list +2)) + if(user_in_netgroup(user, *list +2)) return True; } else { @@ -613,8 +598,7 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, * Just search UNIX list. */ - if(user_in_group_list(user, *list +1, groups, - n_groups)) + if(user_in_group(user, *list +1)) return True; } @@ -624,16 +608,15 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, /* * Search netgroup list followed by UNIX list. */ - if(user_in_netgroup_list(user, *list +2)) + if(user_in_netgroup(user, *list +2)) return True; - if(user_in_group_list(user, *list +2, groups, - n_groups)) + if(user_in_group(user, *list +2)) return True; } else { /* * Just search netgroup list. */ - if(user_in_netgroup_list(user, *list +1)) + if(user_in_netgroup(user, *list +1)) return True; } } else if (!name_is_local(*list)) { @@ -676,7 +659,7 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, /* Check if user name is in the * Windows group */ - ret = user_in_winbind_group_list( + ret = user_in_winbind_group( user, *list, &winbind_answered); @@ -705,21 +688,24 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, it assumes the string starts lowercased ****************************************************************************/ -static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(const char *),int N) +static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, + int offset, + struct passwd *(*fn)(TALLOC_CTX *mem_ctx, const char *), + int N) { ssize_t len = (ssize_t)strlen(s); int i; struct passwd *ret; if (N <= 0 || offset >= len) - return(fn(s)); + return(fn(mem_ctx, s)); for (i=offset;i<(len-(N-1));i++) { char c = s[i]; if (!islower_ascii((int)c)) continue; s[i] = toupper_ascii(c); - ret = uname_string_combinations2(s,i+1,fn,N-1); + ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1); if(ret) return(ret); s[i] = c; @@ -735,13 +721,15 @@ static struct passwd *uname_string_combinations2(char *s,int offset,struct passw it assumes the string starts lowercased ****************************************************************************/ -static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(const char *),int N) +static struct passwd * uname_string_combinations(char *s, TALLOC_CTX *mem_ctx, + struct passwd * (*fn)(TALLOC_CTX *mem_ctx, const char *), + int N) { int n; struct passwd *ret; for (n=1;n<=N;n++) { - ret = uname_string_combinations2(s,0,fn,n); + ret = uname_string_combinations2(s,mem_ctx,0,fn,n); if(ret) return(ret); } diff --git a/source/lib/util.c b/source/lib/util.c index 38878befc77..dc57839df34 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1427,10 +1427,10 @@ const char *uidtoname(uid_t uid) static fstring name; struct passwd *pass; - pass = getpwuid_alloc(uid); + pass = getpwuid_alloc(NULL, uid); if (pass) { fstrcpy(name, pass->pw_name); - passwd_free(&pass); + talloc_free(pass); } else { slprintf(name, sizeof(name) - 1, "%ld",(long int)uid); } @@ -1464,10 +1464,10 @@ uid_t nametouid(const char *name) char *p; uid_t u; - pass = getpwnam_alloc(name); + pass = getpwnam_alloc(NULL, name); if (pass) { u = pass->pw_uid; - passwd_free(&pass); + talloc_free(pass); return u; } diff --git a/source/lib/util_file.c b/source/lib/util_file.c index 407a8b24fc9..53a9bc9b417 100644 --- a/source/lib/util_file.c +++ b/source/lib/util_file.c @@ -386,30 +386,37 @@ char *file_pload(char *syscmd, size_t *size) /**************************************************************************** Load a file into memory from a fd. + Truncate at maxsize. If maxsize == 0 - no limit. ****************************************************************************/ -char *fd_load(int fd, size_t *size) +char *fd_load(int fd, size_t *psize, size_t maxsize) { SMB_STRUCT_STAT sbuf; + size_t size; char *p; if (sys_fstat(fd, &sbuf) != 0) { return NULL; } - p = (char *)SMB_MALLOC(sbuf.st_size+1); + size = sbuf.st_size; + if (maxsize) { + size = MIN(size, maxsize); + } + + p = (char *)SMB_MALLOC(size+1); if (!p) { return NULL; } - if (read(fd, p, sbuf.st_size) != sbuf.st_size) { + if (read(fd, p, size) != size) { SAFE_FREE(p); return NULL; } - p[sbuf.st_size] = 0; + p[size] = 0; - if (size) { - *size = sbuf.st_size; + if (psize) { + *psize = size; } return p; @@ -419,7 +426,7 @@ char *fd_load(int fd, size_t *size) Load a file into memory. ****************************************************************************/ -char *file_load(const char *fname, size_t *size) +char *file_load(const char *fname, size_t *size, size_t maxsize) { int fd; char *p; @@ -433,7 +440,7 @@ char *file_load(const char *fname, size_t *size) return NULL; } - p = fd_load(fd, size); + p = fd_load(fd, size, maxsize); close(fd); return p; } @@ -461,7 +468,7 @@ void *map_file(char *fname, size_t size) } #endif if (!p) { - p = file_load(fname, &s2); + p = file_load(fname, &s2, 0); if (!p) { return NULL; } @@ -522,12 +529,12 @@ static char **file_lines_parse(char *p, size_t size, int *numlines) must be freed with file_lines_free(). ****************************************************************************/ -char **file_lines_load(const char *fname, int *numlines) +char **file_lines_load(const char *fname, int *numlines, size_t maxsize) { char *p; size_t size = 0; - p = file_load(fname, &size); + p = file_load(fname, &size, maxsize); if (!p) { return NULL; } @@ -541,12 +548,12 @@ char **file_lines_load(const char *fname, int *numlines) the list. ****************************************************************************/ -char **fd_lines_load(int fd, int *numlines) +char **fd_lines_load(int fd, int *numlines, size_t maxsize) { char *p; size_t size; - p = fd_load(fd, &size); + p = fd_load(fd, &size, maxsize); if (!p) { return NULL; } diff --git a/source/lib/util_pw.c b/source/lib/util_pw.c index 13349bad34e..e026affb447 100644 --- a/source/lib/util_pw.c +++ b/source/lib/util_pw.c @@ -22,69 +22,45 @@ #include "includes.h" -static struct passwd *alloc_copy_passwd(const struct passwd *from) +static struct passwd *talloc_copy_passwd(TALLOC_CTX *mem_ctx, + const struct passwd *from) { - struct passwd *ret = SMB_XMALLOC_P(struct passwd); - ZERO_STRUCTP(ret); - ret->pw_name = smb_xstrdup(from->pw_name); - ret->pw_passwd = smb_xstrdup(from->pw_passwd); + struct passwd *ret = TALLOC_P(mem_ctx, struct passwd); + ret->pw_name = talloc_strdup(ret, from->pw_name); + ret->pw_passwd = talloc_strdup(ret, from->pw_passwd); ret->pw_uid = from->pw_uid; ret->pw_gid = from->pw_gid; - ret->pw_gecos = smb_xstrdup(from->pw_gecos); - ret->pw_dir = smb_xstrdup(from->pw_dir); - ret->pw_shell = smb_xstrdup(from->pw_shell); + ret->pw_gecos = talloc_strdup(ret, from->pw_gecos); + ret->pw_dir = talloc_strdup(ret, from->pw_dir); + ret->pw_shell = talloc_strdup(ret, from->pw_shell); return ret; } -void passwd_free (struct passwd **buf) -{ - if (!*buf) { - DEBUG(0, ("attempted double-free of allocated passwd\n")); - return; - } - - SAFE_FREE((*buf)->pw_name); - SAFE_FREE((*buf)->pw_passwd); - SAFE_FREE((*buf)->pw_gecos); - SAFE_FREE((*buf)->pw_dir); - SAFE_FREE((*buf)->pw_shell); - - SAFE_FREE(*buf); -} - #define PWNAMCACHE_SIZE 4 -static struct passwd *pwnam_cache[PWNAMCACHE_SIZE]; -static BOOL pwnam_cache_initialized = False; +static struct passwd **pwnam_cache = NULL; static void init_pwnam_cache(void) { - int i; - - if (pwnam_cache_initialized) + if (pwnam_cache != NULL) return; - for (i=0; ipw_name) == 0)) { DEBUG(10, ("Got %s from pwnam_cache\n", name)); - return alloc_copy_passwd(pwnam_cache[i]); + return talloc_reference(mem_ctx, pwnam_cache[i]); } } @@ -119,15 +95,20 @@ struct passwd *getpwnam_alloc(const char *name) if (i == PWNAMCACHE_SIZE) i = rand() % PWNAMCACHE_SIZE; - if (pwnam_cache[i] != NULL) - passwd_free(&pwnam_cache[i]); + if (pwnam_cache[i] != NULL) { + talloc_free(pwnam_cache[i]); + } - pwnam_cache[i] = alloc_copy_passwd(temp); + pwnam_cache[i] = talloc_copy_passwd(pwnam_cache, temp); + + if (mem_ctx != NULL) { + return talloc_reference(mem_ctx, pwnam_cache[i]); + } - return alloc_copy_passwd(temp); + return talloc_copy_passwd(NULL, pwnam_cache[i]); } -struct passwd *getpwuid_alloc(uid_t uid) +struct passwd *getpwuid_alloc(TALLOC_CTX *mem_ctx, uid_t uid) { struct passwd *temp; @@ -142,5 +123,5 @@ struct passwd *getpwuid_alloc(uid_t uid) return NULL; } - return alloc_copy_passwd(temp); + return talloc_copy_passwd(mem_ctx, temp); } diff --git a/source/lib/util_sid.c b/source/lib/util_sid.c index e2b2ebf28ca..c7f9dc2fdbe 100644 --- a/source/lib/util_sid.c +++ b/source/lib/util_sid.c @@ -75,6 +75,11 @@ const DOM_SID global_sid_Builtin_Backup_Operators = /* Builtin backup operators const DOM_SID global_sid_Builtin_Replicator = /* Builtin replicator */ { 1, 2, {0,0,0,0,0,5}, {32,552,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const DOM_SID global_sid_Unix_Users = /* Unmapped Unix users */ +{ 1, 1, {0,0,0,0,0,22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const DOM_SID global_sid_Unix_Groups = /* Unmapped Unix groups */ +{ 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + /* Unused, left here for documentary purposes */ #if 0 #define SECURITY_NULL_SID_AUTHORITY 0 diff --git a/source/lib/util_str.c b/source/lib/util_str.c index 0b02487f774..85b5cfc90a7 100644 --- a/source/lib/util_str.c +++ b/source/lib/util_str.c @@ -1667,7 +1667,7 @@ int fstr_sprintf(fstring s, const char *fmt, ...) #define S_LIST_ABS 16 /* List Allocation Block Size */ -char **str_list_make(const char *string, const char *sep) +static char **str_list_make_internal(TALLOC_CTX *mem_ctx, const char *string, const char *sep) { char **list, **rlist; const char *str; @@ -1677,7 +1677,11 @@ char **str_list_make(const char *string, const char *sep) if (!string || !*string) return NULL; - s = SMB_STRDUP(string); + if (mem_ctx) { + s = talloc_strdup(mem_ctx, string); + } else { + s = SMB_STRDUP(string); + } if (!s) { DEBUG(0,("str_list_make: Unable to allocate memory")); return NULL; @@ -1691,32 +1695,64 @@ char **str_list_make(const char *string, const char *sep) while (next_token(&str, tok, sep, sizeof(tok))) { if (num == lsize) { lsize += S_LIST_ABS; - rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1); + if (mem_ctx) { + rlist = TALLOC_REALLOC_ARRAY(mem_ctx, list, char *, lsize +1); + } else { + rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1); + } if (!rlist) { DEBUG(0,("str_list_make: Unable to allocate memory")); str_list_free(&list); - SAFE_FREE(s); + if (mem_ctx) { + talloc_free(s); + } else { + SAFE_FREE(s); + } return NULL; } else list = rlist; memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1))); } + + if (mem_ctx) { + list[num] = talloc_strdup(mem_ctx, tok); + } else { + list[num] = SMB_STRDUP(tok); + } - list[num] = SMB_STRDUP(tok); if (!list[num]) { DEBUG(0,("str_list_make: Unable to allocate memory")); str_list_free(&list); - SAFE_FREE(s); + if (mem_ctx) { + talloc_free(s); + } else { + SAFE_FREE(s); + } return NULL; } num++; } - - SAFE_FREE(s); + + if (mem_ctx) { + talloc_free(s); + } else { + SAFE_FREE(s); + } + return list; } +char **str_list_make_talloc(TALLOC_CTX *mem_ctx, const char *string, const char *sep) +{ + return str_list_make_internal(mem_ctx, string, sep); +} + +char **str_list_make(const char *string, const char *sep) +{ + return str_list_make_internal(NULL, string, sep); +} + BOOL str_list_copy(char ***dest, const char **src) { char **list, **rlist; @@ -1778,16 +1814,35 @@ BOOL str_list_compare(char **list1, char **list2) return True; } -void str_list_free(char ***list) +static void str_list_free_internal(TALLOC_CTX *mem_ctx, char ***list) { char **tlist; if (!list || !*list) return; tlist = *list; - for(; *tlist; tlist++) - SAFE_FREE(*tlist); - SAFE_FREE(*list); + for(; *tlist; tlist++) { + if (mem_ctx) { + talloc_free(*tlist); + } else { + SAFE_FREE(*tlist); + } + } + if (mem_ctx) { + talloc_free(*tlist); + } else { + SAFE_FREE(*list); + } +} + +void str_list_free_talloc(TALLOC_CTX *mem_ctx, char ***list) +{ + str_list_free_internal(mem_ctx, list); +} + +void str_list_free(char ***list) +{ + str_list_free_internal(NULL, list); } /****************************************************************************** @@ -2317,3 +2372,23 @@ char *sstring_sub(const char *src, char front, char back) temp3[len-1] = '\0'; return temp3; } + +/******************************************************************** + Check a string for any occurrences of a specified list of invalid + characters. +********************************************************************/ + +BOOL validate_net_name( const char *name, const char *invalid_chars, int max_len ) +{ + int i; + + for ( i=0; ibuffer, sizeof(tmp), src->uni_str_len * 2, 0); - if (result < 0) { - return result; - } - - *dest = talloc_strdup(mem_ctx, tmp); - if (*dest == NULL) { - return -1; + if (result == (size_t)-1) { + return NULL; } - return result; + return talloc_strdup(mem_ctx, tmp); } /* Converts a string from internal samba format to unicode diff --git a/source/libads/gpo.c b/source/libads/gpo.c new file mode 100644 index 00000000000..9cf7aae9770 --- /dev/null +++ b/source/libads/gpo.c @@ -0,0 +1,680 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Guenther Deschner 2005 + * + * 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" + +ADS_STATUS ads_parse_gp_ext(TALLOC_CTX *mem_ctx, + const char *extension_raw, + struct GP_EXT *gp_ext) +{ + char **ext_list; + char **ext_strings; + int i; + + DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw)); + + ext_list = str_list_make_talloc(mem_ctx, extension_raw, "]"); + if (ext_list == NULL) { + goto parse_error; + } + + for (i = 0; ext_list[i] != NULL; i++) { + /* no op */ + } + + gp_ext->num_exts = i; + + gp_ext->extensions = TALLOC_ZERO_ARRAY(mem_ctx, char *, gp_ext->num_exts); + gp_ext->extensions_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, gp_ext->num_exts); + gp_ext->snapins = TALLOC_ZERO_ARRAY(mem_ctx, char *, gp_ext->num_exts); + gp_ext->snapins_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, gp_ext->num_exts); + + gp_ext->gp_extension = talloc_strdup(mem_ctx, extension_raw); + + if (gp_ext->extensions == NULL || gp_ext->extensions_guid == NULL || + gp_ext->snapins == NULL || gp_ext->snapins_guid == NULL || + gp_ext->gp_extension == NULL) { + goto parse_error; + } + + for (i = 0; ext_list[i] != NULL; i++) { + + int k; + char *p, *q; + + DEBUGADD(10,("extension #%d\n", i)); + + p = ext_list[i]; + + if (p[0] == '[') { + p++; + } + + ext_strings = str_list_make_talloc(mem_ctx, p, "}"); + if (ext_strings == NULL) { + goto parse_error; + } + + for (k = 0; ext_strings[k] != NULL; k++) { + /* no op */ + } + + q = ext_strings[0]; + + if (q[0] == '{') { + q++; + } + + gp_ext->extensions[i] = talloc_strdup(mem_ctx, cse_gpo_guid_string_to_name(q)); + gp_ext->extensions_guid[i] = talloc_strdup(mem_ctx, q); + + /* we might have no name for the guid */ + if (gp_ext->extensions_guid[i] == NULL) { + goto parse_error; + } + + for (k = 1; ext_strings[k] != NULL; k++) { + + char *m = ext_strings[k]; + + if (m[0] == '{') { + m++; + } + + /* FIXME: theoretically there could be more than one snapin per extension */ + gp_ext->snapins[i] = talloc_strdup(mem_ctx, cse_snapin_gpo_guid_string_to_name(m)); + gp_ext->snapins_guid[i] = talloc_strdup(mem_ctx, m); + + /* we might have no name for the guid */ + if (gp_ext->snapins_guid[i] == NULL) { + goto parse_error; + } + } + } + + if (ext_list) { + str_list_free_talloc(mem_ctx, &ext_list); + } + if (ext_strings) { + str_list_free_talloc(mem_ctx, &ext_strings); + } + + return ADS_ERROR(LDAP_SUCCESS); + +parse_error: + if (ext_list) { + str_list_free_talloc(mem_ctx, &ext_list); + } + if (ext_strings) { + str_list_free_talloc(mem_ctx, &ext_strings); + } + + return ADS_ERROR(LDAP_NO_MEMORY); +} + +ADS_STATUS ads_parse_gplink(TALLOC_CTX *mem_ctx, + const char *gp_link_raw, + uint32 options, + struct GP_LINK *gp_link) +{ + char **link_list; + int i; + + DEBUG(10,("ads_parse_gplink: gPLink: %s\n", gp_link_raw)); + + link_list = str_list_make_talloc(mem_ctx, gp_link_raw, "]"); + if (link_list == NULL) { + goto parse_error; + } + + for (i = 0; link_list[i] != NULL; i++) { + /* no op */ + } + + gp_link->gp_opts = options; + gp_link->num_links = i; + + gp_link->link_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, gp_link->num_links); + gp_link->link_opts = TALLOC_ZERO_ARRAY(mem_ctx, uint32, gp_link->num_links); + + gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw); + + if (gp_link->link_names == NULL || gp_link->link_opts == NULL || gp_link->gp_link == NULL) { + goto parse_error; + } + + for (i = 0; link_list[i] != NULL; i++) { + + char *p, *q; + + DEBUGADD(10,("ads_parse_gplink: processing link #%d\n", i)); + + q = link_list[i]; + if (q[0] == '[') { + q++; + }; + + p = strchr(q, ';'); + + if (p == NULL) { + goto parse_error; + } + + gp_link->link_names[i] = talloc_strdup(mem_ctx, q); + if (gp_link->link_names[i] == NULL) { + goto parse_error; + } + gp_link->link_names[i][PTR_DIFF(p, q)] = 0; + + gp_link->link_opts[i] = atoi(p + 1); + + DEBUGADD(10,("ads_parse_gplink: link: %s\n", gp_link->link_names[i])); + DEBUGADD(10,("ads_parse_gplink: opt: %d\n", gp_link->link_opts[i])); + + } + + if (link_list) { + str_list_free_talloc(mem_ctx, &link_list); + } + + return ADS_ERROR(LDAP_SUCCESS); + +parse_error: + if (link_list) { + str_list_free_talloc(mem_ctx, &link_list); + } + + return ADS_ERROR(LDAP_NO_MEMORY); +} + +ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + struct GP_LINK *gp_link_struct) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", "gPOptions", NULL}; + void *res = NULL; + const char *gp_link; + uint32 gp_options; + + ZERO_STRUCTP(gp_link_struct); + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_get_gpo_link: search failed with %s\n", ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_get_gpo_link: no result\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); + } + + if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) { + DEBUG(10,("ads_get_gpo_link: no 'gPOptions' attribute found\n")); + gp_options = 0; + } + + ads_msgfree(ads, res); + + return ads_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct); +} + +ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + const char *gpo_dn, + uint32 gpo_opt) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", NULL}; + void *res = NULL; + const char *gp_link, *gp_link_new; + ADS_MODLIST mods; + + + /* although ADS allows to set anything here, we better check here if + * the gpo_dn is sane */ + + if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) { + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_add_gpo_link: search failed with %s\n", ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_add_gpo_link: no result\n")); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]", gpo_dn, gpo_opt); + } else { + gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link, gpo_dn, gpo_opt); + } + + if (gp_link_new == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + mods = ads_init_mods(mem_ctx); + if (mods == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); + if (!ADS_ERR_OK(status)) { + return status; + } + + return ads_gen_mod(ads, link_dn, mods); +} + +/* untested & broken */ +ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + const char *gpo_dn) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", NULL}; + void *res = NULL; + const char *gp_link, *gp_link_new = NULL; + ADS_MODLIST mods; + + /* check for a sane gpo_dn */ + if (gpo_dn[0] != '[') { + DEBUG(10,("ads_delete_gpo_link: first char not: [\n")); + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + if (gpo_dn[strlen(gpo_dn)] != ']') { + DEBUG(10,("ads_delete_gpo_link: last char not: ]\n")); + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_delete_gpo_link: search failed with %s\n", ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_delete_gpo_link: no result\n")); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); + } + + /* find link to delete */ +// gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link, gpo_dn, gpo_opt); + + if (gp_link_new == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + mods = ads_init_mods(mem_ctx); + if (mods == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); + if (!ADS_ERR_OK(status)) { + return status; + } + + return ads_gen_mod(ads, link_dn, mods); +} + +ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + void *res, + const char *gpo_dn, + struct GROUP_POLICY_OBJECT *gpo) +{ + ZERO_STRUCTP(gpo); + + if (res == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (gpo_dn) { + gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn); + } else { + gpo->ds_path = ads_get_dn(ads, res); + } + if (gpo->ds_path == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* split here for convenience */ + gpo->version_user = gpo->version >> 16; + gpo->version_machine = gpo->version & 0xffff; + + /* sure ??? */ + if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res, "gPCFileSysPath"); + if (gpo->file_sys_path == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + gpo->display_name = ads_pull_string(ads, mem_ctx, res, "displayName"); + if (gpo->display_name == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + gpo->name = ads_pull_string(ads, mem_ctx, res, "name"); + if (gpo->name == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* ???, this is optional to have and what does it depend on, the 'flags' ?) */ + gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res, "gPCMachineExtensionNames"); + gpo->user_extensions = ads_pull_string(ads, mem_ctx, res, "gPCUserExtensionNames"); + + ads_msgfree(ads, res); + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *gpo_dn, + const char *display_name, + const char *guid_name, + struct GROUP_POLICY_OBJECT *gpo) +{ + ADS_STATUS status; + void *res = NULL; + char *dn; + const char *filter; + const char *attrs[] = { "cn", "displayName", "flags", "gPCFileSysPath", + "gPCFunctionalityVersion", "gPCMachineExtensionNames", + "gPCUserExtensionNames", "gPCWQLFilter", "name", + "versionNumber", NULL}; + + ZERO_STRUCTP(gpo); + + if (!gpo_dn && !display_name && !guid_name) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + if (gpo_dn) { + + if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) { + gpo_dn = gpo_dn + strlen("LDAP://"); + } + + status = ads_search_dn(ads, &res, gpo_dn, attrs); + + } else if (display_name || guid_name) { + + filter = talloc_asprintf(mem_ctx, + "(&(objectclass=groupPolicyContainer)(%s=%s))", + display_name ? "displayName" : "name", + display_name ? display_name : guid_name); + if (filter == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, filter, + attrs, &res); + } + + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_get_gpo: search failed with %s\n", ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_get_gpo: no result\n")); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo); + + ads_memfree(ads, dn); + + return status; +} + +ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + struct GROUP_POLICY_OBJECT **gpo_list, + const char *link_dn, + struct GP_LINK *gp_link, + enum GPO_LINK_TYPE link_type, + BOOL only_add_forced_gpos) +{ + ADS_STATUS status; + int i; + + for (i = 0; i < gp_link->num_links; i++) { + + struct GROUP_POLICY_OBJECT *new_gpo = NULL; + + if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) { + DEBUG(10,("skipping disabled GPO\n")); + continue; + } + + if (only_add_forced_gpos) { + + if (! (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED)) { + DEBUG(10,("skipping nonenforced GPO link because GPOPTIONS_BLOCK_INHERITANCE has been set\n")); + continue; + } else { + DEBUG(10,("adding enforced GPO link although the GPOPTIONS_BLOCK_INHERITANCE has been set\n")); + } + } + + new_gpo = TALLOC_P(mem_ctx, struct GROUP_POLICY_OBJECT); + if (new_gpo == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + ZERO_STRUCTP(new_gpo); + + status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], NULL, NULL, new_gpo); + if (!ADS_ERR_OK(status)) { + return status; + } + + new_gpo->link = link_dn; + new_gpo->link_type = link_type; + + DLIST_ADD(*gpo_list, new_gpo); + + DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s to GPO list\n", + i, gp_link->link_names[i])); + } + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *dn, + uint32 flags, + struct GROUP_POLICY_OBJECT **gpo_list) +{ + /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */ + + ADS_STATUS status; + struct GP_LINK gp_link; + const char *parent_dn, *site_dn, *tmp_dn; + BOOL add_only_forced_gpos = False; + + ZERO_STRUCTP(gpo_list); + + DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn)); + + /* (L)ocal */ + /* not yet... */ + + /* (S)ite */ + + /* are site GPOs valid for users as well ??? */ + if (flags & GPO_LIST_FLAG_MACHINE) { + + status = ads_site_dn_for_machine(ads, mem_ctx, ads->config.ldap_server_name, &site_dn); + if (!ADS_ERR_OK(status)) { + return status; + } + + DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n", site_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list, + site_dn, &gp_link, GP_LINK_SITE, + add_only_forced_gpos); + if (!ADS_ERR_OK(status)) { + return status; + } + + if (flags & GPO_LIST_FLAG_SITEONLY) { + return ADS_ERROR(LDAP_SUCCESS); + } + + /* inheritance can't be blocked at the site level */ + } + } + + tmp_dn = dn; + + while ( (parent_dn = ads_parent_dn(tmp_dn)) && + (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path))) ) { + + /* (D)omain */ + + /* An account can just be a member of one domain */ + if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) { + + DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n", parent_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, parent_dn, &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + /* block inheritance from now on */ + if (gp_link.gp_opts & GPOPTIONS_BLOCK_INHERITANCE) { + add_only_forced_gpos = True; + } + + status = add_gplink_to_gpo_list(ads, mem_ctx, + gpo_list, parent_dn, + &gp_link, GP_LINK_DOMAIN, + add_only_forced_gpos); + if (!ADS_ERR_OK(status)) { + return status; + } + } + } + + tmp_dn = parent_dn; + } + + /* reset dn again */ + tmp_dn = dn; + + while ( (parent_dn = ads_parent_dn(tmp_dn)) && + (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path))) ) { + + + /* (O)rganizational(U)nit */ + + /* An account can be a member of more OUs */ + if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) { + + DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n", parent_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, parent_dn, &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + /* block inheritance from now on */ + if (gp_link.gp_opts & GPOPTIONS_BLOCK_INHERITANCE) { + add_only_forced_gpos = True; + } + + status = add_gplink_to_gpo_list(ads, mem_ctx, + gpo_list, parent_dn, + &gp_link, GP_LINK_OU, + add_only_forced_gpos); + if (!ADS_ERR_OK(status)) { + return status; + } + } + } + + tmp_dn = parent_dn; + + }; + + return ADS_ERROR(LDAP_SUCCESS); +} diff --git a/source/libads/gpo_util.c b/source/libads/gpo_util.c new file mode 100644 index 00000000000..8f913c19714 --- /dev/null +++ b/source/libads/gpo_util.c @@ -0,0 +1,496 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Guenther Deschner 2005 + * + * 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" + +#define DEFAULT_DOMAIN_POLICY "Default Domain Policy" +#define DEFAULT_DOMAIN_CONTROLLERS_POLICY "Default Domain Controllers Policy" + +/* should we store a parsed guid ? UUID_FLAT guid; */ +struct gpo_table { + const char *name; + const char *guid_string; +}; + +struct snapin_table { + const char *name; + const char *guid_string; + ADS_STATUS (*snapin_fn)(ADS_STRUCT *, TALLOC_CTX *mem_ctx, const char *, const char *); +}; + +static struct gpo_table gpo_default_policy[] = { + { DEFAULT_DOMAIN_POLICY, + "31B2F340-016D-11D2-945F-00C04FB984F9" }, + { DEFAULT_DOMAIN_CONTROLLERS_POLICY, + "6AC1786C-016F-11D2-945F-00C04fB984F9" }, + { NULL, NULL } +}; + + +/* the following is seen in gPCMachineExtensionNames or gPCUserExtensionNames */ + +static struct gpo_table gpo_cse_extensions[] = { + { "Administrative Templates Extension", + "35378EAC-683F-11D2-A89A-00C04FBBCFA2" }, /* Registry Policy ? */ + { "Microsoft Disc Quota", + "3610EDA5-77EF-11D2-8DC5-00C04FA31A66" }, + { "EFS recovery", + "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" }, + { "Folder Redirection", + "25537BA6-77A8-11D2-9B6C-0000F8080861" }, + { "IP Security", + "E437BC1C-AA7D-11D2-A382-00C04F991E27" }, + { "Internet Explorer Branding", + "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B" }, + { "QoS Packet Scheduler", + "426031c0-0b47-4852-b0ca-ac3d37bfcb39" }, + { "Scripts", + "42B5FAAE-6536-11D2-AE5A-0000F87571E3" }, + { "Security", + "827D319E-6EAC-11D2-A4EA-00C04F79F83A" }, + { "Software Installation", + "C6DC5466-785A-11D2-84D0-00C04FB169F7" }, + { "Wireless Group Policy", + "0ACDD40C-75AC-BAA0-BF6DE7E7FE63" }, + { NULL, NULL } +}; + +/* guess work */ +static struct snapin_table gpo_cse_snapin_extensions[] = { + { "Administrative Templates", + "0F6B957D-509E-11D1-A7CC-0000F87571E3", gpo_snapin_handler_none }, + { "Certificates", + "53D6AB1D-2488-11D1-A28C-00C04FB94F17", gpo_snapin_handler_none }, + { "EFS recovery policy processing", + "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", gpo_snapin_handler_none }, + { "Folder Redirection policy processing", + "25537BA6-77A8-11D2-9B6C-0000F8080861", gpo_snapin_handler_none }, + { "Folder Redirection", + "88E729D6-BDC1-11D1-BD2A-00C04FB9603F", gpo_snapin_handler_none }, + { "Registry policy processing", + "35378EAC-683F-11D2-A89A-00C04FBBCFA2", gpo_snapin_handler_none }, + { "Remote Installation Services", + "3060E8CE-7020-11D2-842D-00C04FA372D4", gpo_snapin_handler_none }, + { "Security Settings", + "803E14A0-B4FB-11D0-A0D0-00A0C90F574B", gpo_snapin_handler_security_settings }, + { "Security policy processing", + "827D319E-6EAC-11D2-A4EA-00C04F79F83A", gpo_snapin_handler_security_settings }, + { "unknown", + "3060E8D0-7020-11D2-842D-00C04FA372D4", gpo_snapin_handler_none }, + { "unknown2", + "53D6AB1B-2488-11D1-A28C-00C04FB94F17", gpo_snapin_handler_none }, + { NULL, NULL, NULL } +}; + +static const char *name_to_guid_string(const char *name, struct gpo_table *table) +{ + int i; + + for (i = 0; table[i].name; i++) { + if (strequal(name, table[i].name)) { + return table[i].guid_string; + } + } + + return NULL; +} + +static const char *guid_string_to_name(const char *guid_string, struct gpo_table *table) +{ + int i; + + for (i = 0; table[i].guid_string; i++) { + if (strequal(guid_string, table[i].guid_string)) { + return table[i].name; + } + } + + return NULL; +} + +static const char *default_gpo_name_to_guid_string(const char *name) +{ + return name_to_guid_string(name, gpo_default_policy); +} + +static const char *default_gpo_guid_string_to_name(const char *guid) +{ + return guid_string_to_name(guid, gpo_default_policy); +} + +const char *cse_gpo_guid_string_to_name(const char *guid) +{ + return guid_string_to_name(guid, gpo_cse_extensions); +} + +static const char *cse_gpo_name_to_guid_string(const char *name) +{ + return name_to_guid_string(name, gpo_cse_extensions); +} + +const char *cse_snapin_gpo_guid_string_to_name(const char *guid) +{ + return guid_string_to_name(guid, gpo_cse_snapin_extensions); +} + +void dump_gp_ext(struct GP_EXT *gp_ext) +{ + int lvl = 10; + int i; + + if (gp_ext == NULL) { + return; + } + + DEBUG(lvl,("---------------------\n\n")); + DEBUGADD(lvl,("name:\t\t\t%s\n", gp_ext->gp_extension)); + + for (i=0; i< gp_ext->num_exts; i++) { + + DEBUGADD(lvl,("extension:\t\t\t%s\n", gp_ext->extensions_guid[i])); + DEBUGADD(lvl,("extension (name):\t\t\t%s\n", gp_ext->extensions[i])); + + DEBUGADD(lvl,("snapin:\t\t\t%s\n", gp_ext->snapins_guid[i])); + DEBUGADD(lvl,("snapin (name):\t\t\t%s\n", gp_ext->snapins[i])); + } +} + +void dump_gpo(TALLOC_CTX *mem_ctx, struct GROUP_POLICY_OBJECT *gpo) +{ + int lvl = 1; + + if (gpo == NULL) { + return; + } + + DEBUG(lvl,("---------------------\n\n")); + + DEBUGADD(lvl,("name:\t\t\t%s\n", gpo->name)); + DEBUGADD(lvl,("displayname:\t\t%s\n", gpo->display_name)); + DEBUGADD(lvl,("version:\t\t%d (0x%08x)\n", gpo->version, gpo->version)); + DEBUGADD(lvl,("version_user:\t\t%d (0x%04x)\n", gpo->version_user, gpo->version_user)); + DEBUGADD(lvl,("version_machine:\t%d (0x%04x)\n", gpo->version_machine, gpo->version_machine)); + DEBUGADD(lvl,("filesyspath:\t\t%s\n", gpo->file_sys_path)); + DEBUGADD(lvl,("dspath:\t\t%s\n", gpo->ds_path)); + + DEBUGADD(lvl,("options:\t\t%d ", gpo->options)); + if (gpo->options & GPFLAGS_USER_SETTINGS_DISABLED) { + DEBUGADD(lvl,("GPFLAGS_USER_SETTINGS_DISABLED ")); + } + if (gpo->options & GPFLAGS_MACHINE_SETTINGS_DISABLED) { + DEBUGADD(lvl,("GPFLAGS_MACHINE_SETTINGS_DISABLED")); + } + DEBUGADD(lvl,("\n")); + + DEBUGADD(lvl,("link:\t\t\t%s\n", gpo->link)); + DEBUGADD(lvl,("link_type:\t\t%d ", gpo->link_type)); + switch (gpo->link_type) { + case GP_LINK_UNKOWN: + DEBUGADD(lvl,("GP_LINK_UNKOWN\n")); + break; + case GP_LINK_OU: + DEBUGADD(lvl,("GP_LINK_OU\n")); + break; + case GP_LINK_DOMAIN: + DEBUGADD(lvl,("GP_LINK_DOMAIN\n")); + break; + case GP_LINK_SITE: + DEBUGADD(lvl,("GP_LINK_SITE\n")); + break; + case GP_LINK_MACHINE: + DEBUGADD(lvl,("GP_LINK_MACHINE\n")); + break; + default: + break; + } + + if (gpo->machine_extensions) { + + struct GP_EXT gp_ext; + ADS_STATUS status; + + DEBUGADD(lvl,("machine_extensions:\t%s\n", gpo->machine_extensions)); + + status = ads_parse_gp_ext(mem_ctx, gpo->machine_extensions, &gp_ext); + if (!ADS_ERR_OK(status)) { + return; + } + dump_gp_ext(&gp_ext); + } + + if (gpo->user_extensions) { + + struct GP_EXT gp_ext; + ADS_STATUS status; + + DEBUGADD(lvl,("user_extensions:\t%s\n", gpo->user_extensions)); + + status = ads_parse_gp_ext(mem_ctx, gpo->user_extensions, &gp_ext); + if (!ADS_ERR_OK(status)) { + return; + } + dump_gp_ext(&gp_ext); + } +}; + +void dump_gplink(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct GP_LINK *gp_link) +{ + ADS_STATUS status; + int i; + int lvl = 10; + + if (gp_link == NULL) { + return; + } + + DEBUG(lvl,("---------------------\n\n")); + + DEBUGADD(lvl,("gplink: %s\n", gp_link->gp_link)); + DEBUGADD(lvl,("gpopts: %d ", gp_link->gp_opts)); + switch (gp_link->gp_opts) { + case GPOPTIONS_INHERIT: + DEBUGADD(lvl,("GPOPTIONS_INHERIT\n")); + break; + case GPOPTIONS_BLOCK_INHERITANCE: + DEBUGADD(lvl,("GPOPTIONS_BLOCK_INHERITANCE\n")); + break; + default: + break; + } + + DEBUGADD(lvl,("num links: %d\n", gp_link->num_links)); + + for (i = 0; i < gp_link->num_links; i++) { + + DEBUGADD(lvl,("---------------------\n\n")); + + DEBUGADD(lvl,("link: #%d\n", i + 1)); + DEBUGADD(lvl,("name: %s\n", gp_link->link_names[i])); + + DEBUGADD(lvl,("opt: %d ", gp_link->link_opts[i])); + if (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) { + DEBUGADD(lvl,("GPO_LINK_OPT_ENFORCED ")); + } + if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) { + DEBUGADD(lvl,("GPO_LINK_OPT_DISABLED")); + } + DEBUGADD(lvl,("\n")); + + if (ads != NULL && mem_ctx != NULL) { + + struct GROUP_POLICY_OBJECT gpo; + + status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], NULL, NULL, &gpo); + if (!ADS_ERR_OK(status)) { + DEBUG(lvl,("get gpo for %s failed: %s\n", gp_link->link_names[i], ads_errstr(status))); + return; + } + dump_gpo(mem_ctx, &gpo); + } + } +} + +ADS_STATUS process_extension_with_snapin(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *extension_guid, + const char *snapin_guid) +{ + int i; + + for (i=0; gpo_cse_snapin_extensions[i].guid_string; i++) { + + if (strcmp(gpo_cse_snapin_extensions[i].guid_string, snapin_guid) == 0) { + + return gpo_cse_snapin_extensions[i].snapin_fn(ads, mem_ctx, + extension_guid, snapin_guid); + } + } + + DEBUG(10,("process_extension_with_snapin: no snapin handler for extension %s (%s) found\n", + extension_guid, snapin_guid)); + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS gpo_process_a_gpo(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + struct GROUP_POLICY_OBJECT *gpo, + const char *extension_guid, + uint32 flags) +{ + ADS_STATUS status; + struct GP_EXT gp_ext; + int i; + + if (flags & GPO_LIST_FLAG_MACHINE) { + + if (gpo->machine_extensions) { + + status = ads_parse_gp_ext(mem_ctx, gpo->machine_extensions, &gp_ext); + + if (!ADS_ERR_OK(status)) { + return status; + } + + } else { + /* nothing to apply */ + return ADS_ERROR(LDAP_SUCCESS); + } + + } else { + + if (gpo->user_extensions) { + + status = ads_parse_gp_ext(mem_ctx, gpo->user_extensions, &gp_ext); + + if (!ADS_ERR_OK(status)) { + return status; + } + } else { + /* nothing to apply */ + return ADS_ERROR(LDAP_SUCCESS); + } + } + + for (i=0; inext) { + + status = gpo_process_a_gpo(ads, mem_ctx, gpo, + extensions_guid, flags); + + if (!ADS_ERR_OK(status)) { + return status; + } + + } + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS gpo_snapin_handler_none(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *extension_guid, + const char *snapin_guid) +{ + DEBUG(10,("gpo_snapin_handler_none\n")); + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS gpo_snapin_handler_security_settings(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *extension_guid, + const char *snapin_guid) +{ + DEBUG(10,("gpo_snapin_handler_security_settings\n")); + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS gpo_lockout_policy(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *hostname, + SAM_UNK_INFO_12 *lockout_policy) +{ + return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); +} + +ADS_STATUS gpo_password_policy(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *hostname, + SAM_UNK_INFO_1 *password_policy) +{ + ADS_STATUS status; + struct GROUP_POLICY_OBJECT *gpo_list; + const char *attrs[] = {"distinguishedName", "userAccountControl", NULL}; + char *filter, *dn; + void *res = NULL; + uint32 uac; + + return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); + + filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", hostname); + if (filter == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + filter, attrs, &res); + + if (!ADS_ERR_OK(status)) { + return status; + } + + if (ads_count_replies(ads, res) != 1) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (!(uac & UF_WORKSTATION_TRUST_ACCOUNT)) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + status = ads_get_gpo_list(ads, mem_ctx, dn, GPO_LIST_FLAG_MACHINE, &gpo_list); + if (!ADS_ERR_OK(status)) { + return status; + } + + status = gpo_process_gpo_list(ads, mem_ctx, &gpo_list, + cse_gpo_name_to_guid_string("Security"), + GPO_LIST_FLAG_MACHINE); + if (!ADS_ERR_OK(status)) { + return status; + } + + return ADS_ERROR(LDAP_SUCCESS); +} diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c index d5b4b11fa24..67f84337757 100644 --- a/source/libads/kerberos.c +++ b/source/libads/kerberos.c @@ -62,13 +62,17 @@ int kerberos_kinit_password(const char *principal, const char *password, int time_offset, time_t *expire_time, - const char *cache_name) + time_t *renew_till_time, + const char *cache_name, + BOOL request_pac, + time_t renewable_time) { krb5_context ctx = NULL; krb5_error_code code = 0; krb5_ccache cc = NULL; krb5_principal me; krb5_creds my_creds; + krb5_get_init_creds_opt opt; initialize_krb5_error_table(); if ((code = krb5_init_context(&ctx))) @@ -77,9 +81,11 @@ int kerberos_kinit_password(const char *principal, if (time_offset != 0) { krb5_set_real_time(ctx, time(NULL) + time_offset, 0); } - - if ((code = krb5_cc_resolve(ctx, cache_name ? - cache_name : krb5_cc_default_name(ctx), &cc))) { + + DEBUG(10,("kerberos_kinit_password: using %s as ccache\n", + cache_name ? cache_name: krb5_cc_default_name(ctx))); + + if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) { krb5_free_context(ctx); return code; } @@ -88,10 +94,20 @@ int kerberos_kinit_password(const char *principal, krb5_free_context(ctx); return code; } + + krb5_get_init_creds_opt_init(&opt); + krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time); + krb5_get_init_creds_opt_set_forwardable(&opt, 1); + if (request_pac) { +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST + krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True); +#endif + } + if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), kerb_prompter, - NULL, 0, NULL, NULL))) { + NULL, 0, NULL, &opt))) { krb5_free_principal(ctx, me); krb5_free_context(ctx); return code; @@ -111,9 +127,14 @@ int kerberos_kinit_password(const char *principal, krb5_free_context(ctx); return code; } - - if (expire_time) + + if (expire_time) { *expire_time = (time_t) my_creds.times.endtime; + } + + if (renew_till_time) { + *renew_till_time = (time_t) my_creds.times.renew_till; + } krb5_cc_close(ctx, cc); krb5_free_cred_contents(ctx, &my_creds); @@ -157,7 +178,7 @@ int ads_kinit_password(ADS_STRUCT *ads) } ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset, - &ads->auth.expire, NULL); + &ads->auth.expire, NULL, NULL, False, ads->auth.renewable); if (ret) { DEBUG(0,("kerberos_kinit_password %s failed: %s\n", @@ -349,7 +370,8 @@ static krb5_error_code get_service_ticket(krb5_context ctx, if (password == NULL) { goto out; } - if ((err = kerberos_kinit_password(machine_account, password, 0, NULL, LIBADS_CCACHE_NAME)) != 0) { + if ((err = kerberos_kinit_password(machine_account, password, 0, NULL, NULL, + LIBADS_CCACHE_NAME, False, 0)) != 0) { DEBUG(0,("get_service_ticket: kerberos_kinit_password %s@%s failed: %s\n", machine_account, lp_realm(), diff --git a/source/libads/krb5_errs.c b/source/libads/krb5_errs.c new file mode 100644 index 00000000000..cd227d4377c --- /dev/null +++ b/source/libads/krb5_errs.c @@ -0,0 +1,132 @@ +/* + * Unix SMB/CIFS implementation. + * Kerberos error mapping functions + * Copyright (C) Guenther Deschner 2005 + * + * 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 + +static const struct { + int krb5_code; + NTSTATUS ntstatus; +} krb5_to_nt_status_map[] = { + {KRB5_CC_IO, NT_STATUS_UNEXPECTED_IO_ERROR}, + {KRB5KDC_ERR_BADOPTION, NT_STATUS_INVALID_PARAMETER}, + {KRB5KDC_ERR_CLIENT_REVOKED, NT_STATUS_ACCESS_DENIED}, + {KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME}, + {KRB5KDC_ERR_ETYPE_NOSUPP, NT_STATUS_LOGON_FAILURE}, +#if defined(KRB5KDC_ERR_KEY_EXPIRED) /* Heimdal */ + {KRB5KDC_ERR_KEY_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, +#elif defined(KRB5KDC_ERR_KEY_EXP) /* MIT */ + {KRB5KDC_ERR_KEY_EXP, NT_STATUS_PASSWORD_EXPIRED}, +#else +#error Neither KRB5KDC_ERR_KEY_EXPIRED nor KRB5KDC_ERR_KEY_EXP available +#endif + {25, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: bug in heimdal 0.7 krb5_get_init_creds_password (Inappropriate ioctl for device (25)) */ + {KRB5KDC_ERR_NULL_KEY, NT_STATUS_LOGON_FAILURE}, + {KRB5KDC_ERR_POLICY, NT_STATUS_PASSWORD_RESTRICTION}, + {KRB5KDC_ERR_PREAUTH_FAILED, NT_STATUS_LOGON_FAILURE}, + {KRB5KDC_ERR_SERVICE_REVOKED, NT_STATUS_ACCESS_DENIED}, + {KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME}, + {KRB5KDC_ERR_SUMTYPE_NOSUPP, NT_STATUS_LOGON_FAILURE}, + {KRB5KDC_ERR_TGT_REVOKED, NT_STATUS_ACCESS_DENIED}, + {KRB5_KDC_UNREACH, NT_STATUS_NO_LOGON_SERVERS}, + {KRB5KRB_AP_ERR_BAD_INTEGRITY, NT_STATUS_LOGON_FAILURE}, + {KRB5KRB_AP_ERR_MODIFIED, NT_STATUS_LOGON_FAILURE}, + {KRB5KRB_AP_ERR_SKEW, NT_STATUS_TIME_DIFFERENCE_AT_DC}, + {KRB5KRB_AP_ERR_TKT_EXPIRED, NT_STATUS_LOGON_FAILURE}, + {KRB5KRB_ERR_GENERIC, NT_STATUS_UNSUCCESSFUL}, + {KRB5KRB_ERR_RESPONSE_TOO_BIG, NT_STATUS_PROTOCOL_UNREACHABLE}, + {0, NT_STATUS_OK} +}; + +static const struct { + NTSTATUS ntstatus; + int krb5_code; +} nt_status_to_krb5_map[] = { + {NT_STATUS_LOGON_FAILURE, KRB5KDC_ERR_PREAUTH_FAILED}, + {NT_STATUS_NO_LOGON_SERVERS, KRB5_KDC_UNREACH}, + {NT_STATUS_OK, 0} +}; + +/***************************************************************************** +convert a KRB5 error to a NT status32 code + *****************************************************************************/ +NTSTATUS krb5_to_nt_status(int kerberos_error) +{ + int i; + + if (kerberos_error == 0) { + return NT_STATUS_OK; + } + + for (i=0; NT_STATUS_V(krb5_to_nt_status_map[i].ntstatus); i++) { + if (kerberos_error == krb5_to_nt_status_map[i].krb5_code) + return krb5_to_nt_status_map[i].ntstatus; + } + + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a KRB5 error + *****************************************************************************/ +int nt_status_to_krb5(NTSTATUS nt_status) +{ + int i; + + if NT_STATUS_IS_OK(nt_status) { + return 0; + } + + for (i=0; NT_STATUS_V(nt_status_to_krb5_map[i].ntstatus); i++) { + if (NT_STATUS_EQUAL(nt_status,nt_status_to_krb5_map[i].ntstatus)) + return nt_status_to_krb5_map[i].krb5_code; + } + + return KRB5KRB_ERR_GENERIC; +} + +#else + +/***************************************************************************** +convert a KRB5 error to a NT status32 code + *****************************************************************************/ +NTSTATUS krb5_to_nt_status(int kerberos_error) +{ + if (kerberos_error == 0) { + return NT_STATUS_OK; + } + + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a KRB5 error + *****************************************************************************/ +int nt_status_to_krb5(NTSTATUS nt_status) +{ + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) { + return 0; + } + return -1; /* FIXME: what to return here ? */ +} + +#endif + diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c index 31d0a02cad0..6ffd218e966 100644 --- a/source/libads/krb5_setpw.c +++ b/source/libads/krb5_setpw.c @@ -24,9 +24,17 @@ #ifdef HAVE_KRB5 #define DEFAULT_KPASSWD_PORT 464 + #define KRB5_KPASSWD_VERS_CHANGEPW 1 + #define KRB5_KPASSWD_VERS_SETPW 0xff80 #define KRB5_KPASSWD_VERS_SETPW_ALT 2 + +#define KRB5_KPASSWD_SUCCESS 0 +#define KRB5_KPASSWD_MALFORMED 1 +#define KRB5_KPASSWD_HARDERROR 2 +#define KRB5_KPASSWD_AUTHERROR 3 +#define KRB5_KPASSWD_SOFTERROR 4 #define KRB5_KPASSWD_ACCESSDENIED 5 #define KRB5_KPASSWD_BAD_VERSION 6 #define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7 @@ -213,6 +221,25 @@ static krb5_error_code setpw_result_code_string(krb5_context context, return (0); } + krb5_error_code kpasswd_err_to_krb5_err(krb5_error_code res_code) +{ + switch(res_code) { + case KRB5_KPASSWD_ACCESSDENIED: + return KRB5KDC_ERR_BADOPTION; + case KRB5_KPASSWD_INITIAL_FLAG_NEEDED: + return KRB5KDC_ERR_BADOPTION; + /* return KV5M_ALT_METHOD; MIT-only define */ + case KRB5_KPASSWD_ETYPE_NOSUPP: + return KRB5KDC_ERR_ETYPE_NOSUPP; + case KRB5_KPASSWD_BAD_PRINCIPAL: + return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + case KRB5_KPASSWD_POLICY_REJECT: + case KRB5_KPASSWD_SOFTERROR: + return KRB5KDC_ERR_POLICY; + default: + return KRB5KRB_ERR_GENERIC; + } +} static krb5_error_code parse_setpw_reply(krb5_context context, krb5_auth_context auth_context, krb5_data *packet) @@ -312,23 +339,9 @@ static krb5_error_code parse_setpw_reply(krb5_context context, else { const char *errstr; setpw_result_code_string(context, res_code, &errstr); - DEBUG(1, ("Error changing password: %s\n", errstr)); - - switch(res_code) { - case KRB5_KPASSWD_ACCESSDENIED: - return KRB5KDC_ERR_BADOPTION; - case KRB5_KPASSWD_INITIAL_FLAG_NEEDED: - return KRB5KDC_ERR_BADOPTION; - /* return KV5M_ALT_METHOD; MIT-only define */ - case KRB5_KPASSWD_ETYPE_NOSUPP: - return KRB5KDC_ERR_ETYPE_NOSUPP; - case KRB5_KPASSWD_BAD_PRINCIPAL: - return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; - case KRB5_KPASSWD_POLICY_REJECT: - return KRB5KDC_ERR_POLICY; - default: - return KRB5KRB_ERR_GENERIC; - } + DEBUG(1, ("Error changing password: %s (%d)\n", errstr, res_code)); + + return kpasswd_err_to_krb5_err(res_code); } } @@ -664,7 +677,7 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server, { int ret; - if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL, NULL))) { + if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL, NULL, NULL, False, 0))) { DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret))); return ADS_ERROR_KRB5(ret); } diff --git a/source/libads/ldap.c b/source/libads/ldap.c index e503da62a47..8444989bac3 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Tridgell 2001 Copyright (C) Remus Koos 2001 Copyright (C) Jim McDonough 2002 + Copyright (C) Guenther Deschner 2005 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 @@ -807,6 +808,65 @@ char *ads_get_dn(ADS_STRUCT *ads, void *msg) return unix_dn; } +/** + * Get a canonical dn from search results + * @param ads connection to ads server + * @param msg Search result + * @return dn string + **/ +char *ads_get_dn_canonical(ADS_STRUCT *ads, void *msg) +{ +#ifdef HAVE_LDAP_DN2AD_CANONICAL + return ldap_dn2ad_canonical(ads_get_dn(ads, msg)); +#else + return NULL; +#endif +} + + +/** + * Get the parent dn from a search result + * @param ads connection to ads server + * @param msg Search result + * @return parent dn string + **/ +char *ads_get_parent_dn(ADS_STRUCT *ads, void *msg) +{ + char *mydn, *p, *dn; + + dn = ads_get_dn(ads, msg); + if (dn == NULL) { + return NULL; + } + + mydn = dn; + ads_memfree(ads, dn); + + p = strchr(mydn, ','); + + if (p == NULL) { + return NULL; + } + + return p+1; +} + +/** + * Get the parent from a dn + * @param dn the dn to return the parent from + * @return parent dn string + **/ +char *ads_parent_dn(const char *dn) +{ + char *p = strchr(dn, ','); + + if (p == NULL) { + return NULL; + } + + return p+1; +} + /** * Find a machine account given a hostname * @param ads connection to ads server @@ -2700,4 +2760,167 @@ ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char * return ADS_SUCCESS; } +/** + * find our site name + * @param ads connection to ads server + * @param mem_ctx Pointer to talloc context + * @param site_name Pointer to the sitename + * @return status of search + **/ +ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name) +{ + ADS_STATUS status; + void *res; + const char *dn, *service_name; + const char *attrs[] = { "dsServiceName", NULL }; + + status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); + if (!ADS_ERR_OK(status)) { + return status; + } + + service_name = ads_pull_string(ads, mem_ctx, res, "dsServiceName"); + if (service_name == NULL) { + return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); + } + + /* go up three levels */ + dn = ads_parent_dn(ads_parent_dn(ads_parent_dn(service_name))); + if (dn == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + *site_name = talloc_strdup(mem_ctx, dn); + if (*site_name == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + ads_msgfree(ads, res); + + return status; + /* + dsServiceName: CN=NTDS Settings,CN=W2K3DC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ber,DC=suse,DC=de + */ +} + +/** + * find the site dn where a machine resides + * @param ads connection to ads server + * @param mem_ctx Pointer to talloc context + * @param computer_name name of the machine + * @param site_name Pointer to the sitename + * @return status of search + **/ +ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn) +{ + ADS_STATUS status; + void *res; + const char *parent, *config_context, *filter; + const char *attrs[] = { "configurationNamingContext", NULL }; + char *dn; + + /* shortcut a query */ + if (strequal(computer_name, ads->config.ldap_server_name)) { + return ads_site_dn(ads, mem_ctx, site_dn); + } + + status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); + if (!ADS_ERR_OK(status)) { + return status; + } + + config_context = ads_pull_string(ads, mem_ctx, res, "configurationNamingContext"); + if (config_context == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + filter = talloc_asprintf(mem_ctx, "(cn=%s)", computer_name); + if (filter == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_do_search(ads, config_context, LDAP_SCOPE_SUBTREE, filter, NULL, &res); + if (!ADS_ERR_OK(status)) { + return status; + } + + if (ads_count_replies(ads, res) != 1) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* go up three levels */ + parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn))); + if (parent == NULL) { + ads_memfree(ads, dn); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + *site_dn = talloc_strdup(mem_ctx, parent); + if (*site_dn == NULL) { + ads_memfree(ads, dn); + ADS_ERROR(LDAP_NO_MEMORY); + } + + ads_memfree(ads, dn); + ads_msgfree(ads, res); + + return status; +} + +/** + * get the upn suffixes for a domain + * @param ads connection to ads server + * @param mem_ctx Pointer to talloc context + * @param suffixes Pointer to an array of suffixes + * @param site_name Pointer to the number of suffixes + * @return status of search + **/ +ADS_STATUS ads_upn_suffixes(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **suffixes, size_t *num_suffixes) +{ + ADS_STATUS status; + void *res; + const char *config_context, *base; + const char *attrs[] = { "configurationNamingContext", NULL }; + const char *attrs2[] = { "uPNSuffixes", NULL }; + + status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); + if (!ADS_ERR_OK(status)) { + return status; + } + + config_context = ads_pull_string(ads, mem_ctx, res, "configurationNamingContext"); + if (config_context == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + base = talloc_asprintf(mem_ctx, "cn=Partitions,%s", config_context); + if (base == NULL) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_search_dn(ads, &res, base, attrs2); + if (!ADS_ERR_OK(status)) { + return status; + } + + if (ads_count_replies(ads, res) != 1) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + suffixes = ads_pull_strings(ads, mem_ctx, &res, "uPNSuffixes", num_suffixes); + if (suffixes == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + ads_msgfree(ads, res); + + return status; +} + #endif diff --git a/source/libads/sasl.c b/source/libads/sasl.c index f6adfb51086..d8d33a924f2 100644 --- a/source/libads/sasl.c +++ b/source/libads/sasl.c @@ -294,16 +294,28 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) /* we need to fetch a service ticket as the ldap user in the servers realm, regardless of our realm */ asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm); - krb5_init_context(&ctx); - krb5_set_default_tgs_ktypes(ctx, enc_types); - krb5_parse_name(ctx, sname, &principal); + + initialize_krb5_error_table(); + status = ADS_ERROR_KRB5(krb5_init_context(&ctx)); + if (!ADS_ERR_OK(status)) { + return status; + } + status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types)); + if (!ADS_ERR_OK(status)) { + return status; + } + status = ADS_ERROR_KRB5(krb5_parse_name(ctx, sname, &principal)); + if (!ADS_ERR_OK(status)) { + return status; + } + free(sname); krb5_free_context(ctx); input_name.value = &principal; input_name.length = sizeof(principal); - gss_rc = gss_import_name(&minor_status,&input_name,&nt_principal, &serv_name); + gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name); if (gss_rc) { return ADS_ERROR_GSS(gss_rc, minor_status); } @@ -375,8 +387,9 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) p = (uint8 *)output_token.value; +#if 0 file_save("sasl_gssapi.dat", output_token.value, output_token.length); - +#endif max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3]; sec_layer = *p; diff --git a/source/libmsrpc/cac_lsarpc.c b/source/libmsrpc/cac_lsarpc.c index d2e52f01a4c..b157f33c69f 100644 --- a/source/libmsrpc/cac_lsarpc.c +++ b/source/libmsrpc/cac_lsarpc.c @@ -298,7 +298,7 @@ int cac_LsaGetSidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Ls /*now actually lookup the names*/ hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, num_names, - (const char **)op->in.names, &sids, &types); + (const char **)op->in.names, NULL, &sids, &types); if(NT_STATUS_IS_OK(hnd->status)) { /*this is the easy part, just make the out.sids array*/ @@ -577,7 +577,7 @@ int cac_LsaEnumAccountRights(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct L uint32 *type; /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; @@ -799,7 +799,7 @@ int cac_LsaOpenAccount(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpen uint32 *type; /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; @@ -859,7 +859,7 @@ int cac_LsaAddPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAd if(op->in.name && !op->in.sid) { /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; @@ -909,7 +909,7 @@ int cac_LsaRemovePrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Ls if(op->in.name && !op->in.sid) { /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; @@ -959,7 +959,7 @@ int cac_LsaClearPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Lsa if(op->in.name && !op->in.sid) { /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; @@ -1008,7 +1008,7 @@ int cac_LsaSetPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAd if(op->in.name && !op->in.sid) { /*lookup the SID*/ - hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type); + hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), NULL, &user_sid, &type); if(!NT_STATUS_IS_OK(hnd->status)) return CAC_FAILURE; diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index 7c15c8d19f2..6f32fb1b5d4 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -756,7 +756,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, int ret; use_in_memory_ccache(); - ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL); + ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL, NULL, False, 0); if (ret){ SAFE_FREE(principal); diff --git a/source/libsmb/clidfs.c b/source/libsmb/clidfs.c index 51f21397f7c..c5cf75783ba 100644 --- a/source/libsmb/clidfs.c +++ b/source/libsmb/clidfs.c @@ -682,12 +682,15 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; - struct cli_state *cli_ipc; pstring fullpath; + BOOL res; + uint16 cnum; if ( !cli || !sharename ) return False; + cnum = cli->cnum; + /* special case. never check for a referral on the IPC$ share */ if ( strequal( sharename, "IPC$" ) ) @@ -699,12 +702,19 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, /* check for the referral */ - if ( !(cli_ipc = cli_cm_open( cli->desthost, "IPC$", False )) ) + if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) { return False; - - if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed) - || !num_refs ) - { + } + + res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed); + + if (!cli_tdis(cli)) { + return False; + } + + cli->cnum = cnum; + + if (!res || !num_refs ) { return False; } diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c index 2f980adcf87..55addd44a61 100644 --- a/source/libsmb/clientgen.c +++ b/source/libsmb/clientgen.c @@ -353,11 +353,14 @@ struct cli_state *cli_initialise(struct cli_state *cli) /**************************************************************************** External interface. Close an open named pipe over SMB. Free any authentication data. + Returns False if the cli_close call failed. ****************************************************************************/ -void cli_rpc_pipe_close(struct rpc_pipe_client *cli) +BOOL cli_rpc_pipe_close(struct rpc_pipe_client *cli) { - if (!cli_close(cli->cli, cli->fnum)) { + BOOL ret = cli_close(cli->cli, cli->fnum); + + if (!ret) { DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s, " "fnum 0x%x " "to machine %s. Error was %s\n", @@ -376,6 +379,7 @@ void cli_rpc_pipe_close(struct rpc_pipe_client *cli) DLIST_REMOVE(cli->cli->pipe_list, cli); talloc_destroy(cli->mem_ctx); + return ret; } /**************************************************************************** diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c index e0dcefeb1d7..55a705d7f0f 100644 --- a/source/libsmb/clikrb5.c +++ b/source/libsmb/clikrb5.c @@ -409,9 +409,10 @@ static BOOL ads_cleanup_expired_creds(krb5_context context, krb5_creds *credsp) { krb5_error_code retval; + const char *cc_type = krb5_cc_get_type(context, ccache); - DEBUG(3, ("Ticket in ccache[%s] expiration %s\n", - krb5_cc_default_name(context), + DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n", + cc_type, krb5_cc_get_name(context, ccache), http_timestring(credsp->times.endtime))); /* we will probably need new tickets if the current ones @@ -425,11 +426,11 @@ static BOOL ads_cleanup_expired_creds(krb5_context context, use memory ccaches, and a FILE one probably means that we're using creds obtained outside of our exectuable */ - if (StrCaseCmp(krb5_cc_get_type(context, ccache), "FILE") == 0) { - DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a FILE ccache\n")); + if (strequal(cc_type, "KCM") || strequal(cc_type, "FILE")) { + DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type)); return False; } - + retval = krb5_cc_remove_cred(context, ccache, 0, credsp); if (retval) { DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n", @@ -467,7 +468,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context, /* obtain ticket & session key */ ZERO_STRUCT(creds); if ((retval = krb5_copy_principal(context, server, &creds.server))) { - DEBUG(1,("krb5_copy_principal failed (%s)\n", + DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", error_message(retval))); goto cleanup_princ; } @@ -502,8 +503,8 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context, i++; } - DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s) is valid until: (%s - %u)\n", - principal, krb5_cc_default_name(context), + DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n", + principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache), http_timestring((unsigned)credsp->times.endtime), (unsigned)credsp->times.endtime)); @@ -530,7 +531,8 @@ cleanup_princ: get a kerberos5 ticket for the given service */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, - DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts) + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, + uint32 extra_ap_opts, const char *ccname) { krb5_error_code retval; krb5_data packet; @@ -544,7 +546,7 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC, ENCTYPE_NULL}; - + initialize_krb5_error_table(); retval = krb5_init_context(&context); if (retval) { @@ -557,7 +559,8 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset, krb5_set_real_time(context, time(NULL) + time_offset, 0); } - if ((retval = krb5_cc_default(context, &ccdef))) { + if ((retval = krb5_cc_resolve(context, ccname ? + ccname : krb5_cc_default_name(context), &ccdef))) { DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n", error_message(retval))); goto failed; @@ -989,12 +992,156 @@ out: #else #error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION #endif +} + + krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */ + const char *client_string, /* gd@BER.SUSE.DE */ + const char *service_string, /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */ + time_t *new_start_time) +{ + krb5_error_code ret; + krb5_context context = NULL; + krb5_ccache ccache = NULL; + krb5_principal client = NULL; + + initialize_krb5_error_table(); + ret = krb5_init_context(&context); + if (ret) { + goto done; + } + + if (!ccache_string) { + ccache_string = krb5_cc_default_name(context); + } + + DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string)); + + /* FIXME: we should not fall back to defaults */ + ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache); + if (ret) { + goto done; + } + +#ifdef HAVE_KRB5_GET_RENEWED_CREDS /* MIT */ + { + krb5_creds creds; + + if (client_string) { + ret = krb5_parse_name(context, client_string, &client); + if (ret) { + goto done; + } + } else { + ret = krb5_cc_get_principal(context, ccache, &client); + if (ret) { + goto done; + } + } + + ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string)); + if (ret) { + DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret))); + goto done; + } + + /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */ + ret = krb5_cc_initialize(context, ccache, client); + if (ret) { + goto done; + } + + ret = krb5_cc_store_cred(context, ccache, &creds); + + if (new_start_time) { + *new_start_time = (time_t) creds.times.renew_till; + } + + krb5_free_cred_contents(context, &creds); + } +#elif defined(HAVE_KRB5_GET_KDC_CRED) /* Heimdal */ + { + krb5_kdc_flags flags; + krb5_creds creds_in; + krb5_realm *client_realm; + krb5_creds *creds; + + memset(&creds_in, 0, sizeof(creds_in)); + + if (client_string) { + ret = krb5_parse_name(context, client_string, &creds_in.client); + if (ret) { + goto done; + } + } else { + ret = krb5_cc_get_principal(context, ccache, &creds_in.client); + if (ret) { + goto done; + } + } + + if (service_string) { + ret = krb5_parse_name(context, service_string, &creds_in.server); + if (ret) { + goto done; + } + } else { + /* build tgt service by default */ + client_realm = krb5_princ_realm(context, client); + ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL); + if (ret) { + goto done; + } + } + + flags.i = 0; + flags.b.renewable = flags.b.renew = True; + + ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds); + if (ret) { + DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret))); + goto done; + } + + /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */ + ret = krb5_cc_initialize(context, ccache, creds_in.client); + if (ret) { + goto done; + } + + ret = krb5_cc_store_cred(context, ccache, creds); + + if (new_start_time) { + *new_start_time = (time_t) creds->times.renew_till; + } + + krb5_free_cred_contents(context, &creds_in); + krb5_free_creds(context, creds); + } +#else +#error No suitable krb5 ticket renew function available +#endif + + +done: + if (client) { + krb5_free_principal(context, client); + } + if (context) { + krb5_free_context(context); + } + if (ccache) { + krb5_cc_close(context, ccache); + } + + return ret; + } #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, - DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts) + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts, + const char *ccname) { DEBUG(0,("NO KERBEROS SUPPORT\n")); return 1; diff --git a/source/libsmb/clilist.c b/source/libsmb/clilist.c index 48780e28dfa..252dafcfa8b 100644 --- a/source/libsmb/clilist.c +++ b/source/libsmb/clilist.c @@ -169,7 +169,11 @@ static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,f int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, void (*fn)(const char *, file_info *, const char *, void *), void *state) { - int max_matches = 1366; +#if 1 + int max_matches = 1366; /* Match W2k - was 512. */ +#else + int max_matches = 512; +#endif int info_level; char *p, *p2; pstring mask; diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c index cc481a066ab..13bf1a866c9 100644 --- a/source/libsmb/clispnego.c +++ b/source/libsmb/clispnego.c @@ -333,7 +333,7 @@ int spnego_gen_negTokenTarg(const char *principal, int time_offset, /* get a kerberos ticket for the service and extract the session key */ retval = cli_krb5_get_ticket(principal, time_offset, - &tkt, session_key_krb5, extra_ap_opts); + &tkt, session_key_krb5, extra_ap_opts, NULL); if (retval) return retval; diff --git a/source/libsmb/conncache.c b/source/libsmb/conncache.c index 2af4d57b804..49512d7a2e5 100644 --- a/source/libsmb/conncache.c +++ b/source/libsmb/conncache.c @@ -25,8 +25,6 @@ #include "includes.h" -#define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */ - #define CONNCACHE_ADDR 1 #define CONNCACHE_NAME 2 @@ -44,10 +42,13 @@ struct failed_connection_cache { static struct failed_connection_cache *failed_connection_cache; /********************************************************************** - Check for a previously failed connection + Check for a previously failed connection. + failed_cache_timeout is an a absolute number of seconds after which + we should time this out. If failed_cache_timeout == 0 then time out + immediately. If failed_cache_timeout == -1 then never time out. **********************************************************************/ -NTSTATUS check_negative_conn_cache( const char *domain, const char *server ) +NTSTATUS check_negative_conn_cache_timeout( const char *domain, const char *server, unsigned int failed_cache_timeout ) { struct failed_connection_cache *fcc; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; @@ -59,22 +60,24 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server ) for (fcc = failed_connection_cache; fcc; fcc = fcc->next) { - if ( !(strequal(domain, fcc->domain_name) && strequal(server, fcc->controller)) ) + if (!(strequal(domain, fcc->domain_name) && strequal(server, fcc->controller))) { continue; /* no match; check the next entry */ + } /* we have a match so see if it is still current */ + if (failed_cache_timeout != (unsigned int)-1) { + if (failed_cache_timeout == 0 || + (time(NULL) - fcc->lookup_time) > (time_t)failed_cache_timeout) { + /* Cache entry has expired, delete it */ - if ((time(NULL) - fcc->lookup_time) > FAILED_CONNECTION_CACHE_TIMEOUT) - { - /* Cache entry has expired, delete it */ - - DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n", - domain, server )); + DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n", + domain, server )); - DLIST_REMOVE(failed_connection_cache, fcc); - SAFE_FREE(fcc); + DLIST_REMOVE(failed_connection_cache, fcc); + SAFE_FREE(fcc); - return NT_STATUS_OK; + return NT_STATUS_OK; + } } /* The timeout hasn't expired yet so return false */ @@ -90,6 +93,11 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server ) return NT_STATUS_OK; } +NTSTATUS check_negative_conn_cache( const char *domain, const char *server) +{ + return check_negative_conn_cache_timeout(domain, server, FAILED_CONNECTION_CACHE_TIMEOUT); +} + /********************************************************************** Add an entry to the failed conneciton cache (aither a name of dotted decimal IP diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c index 3c0b13ad6ff..f6b5af068a5 100644 --- a/source/libsmb/errormap.c +++ b/source/libsmb/errormap.c @@ -1411,6 +1411,13 @@ static const struct { {NT_STATUS(0x80000289), W_ERROR(0x48e)}, {NT_STATUS_OK, WERR_OK}}; +static const struct { + WERROR werror; + NTSTATUS ntstatus; +} werror_to_ntstatus_map[] = { + { W_ERROR(0x5), NT_STATUS_ACCESS_DENIED }, + { WERR_OK, NT_STATUS_OK } +}; /***************************************************************************** convert a dos eclas/ecode to a NT status32 code @@ -1460,6 +1467,14 @@ NTSTATUS werror_to_ntstatus(WERROR error) { int i; if (W_ERROR_IS_OK(error)) return NT_STATUS_OK; + + for (i=0; !W_ERROR_IS_OK(werror_to_ntstatus_map[i].werror); i++) { + if (W_ERROR_V(error) == + W_ERROR_V(werror_to_ntstatus_map[i].werror)) { + return werror_to_ntstatus_map[i].ntstatus; + } + } + for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) { if (W_ERROR_V(error) == W_ERROR_V(ntstatus_to_werror_map[i].werror)) { diff --git a/source/libsmb/gpo.c b/source/libsmb/gpo.c new file mode 100644 index 00000000000..0257138ece2 --- /dev/null +++ b/source/libsmb/gpo.c @@ -0,0 +1,167 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Guenther Deschner 2005 + * + * 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" + +#define GPT_INI_SECTION_GENERAL "General" +#define GPT_INI_PARAMETER_VERSION "Version" +#define GPT_INI_PARAMETER_DISPLAYNAME "displayName" + +struct gpt_ini { + uint32 version; + const char *display_name; +}; + +static uint32 version; + +static BOOL do_section(const char *section) +{ + DEBUG(10,("do_section: %s\n", section)); + + return True; +} + +static BOOL do_parameter(const char *parameter, const char *value) +{ + DEBUG(10,("do_parameter: %s, %s\n", parameter, value)); + + if (strequal(parameter, GPT_INI_PARAMETER_VERSION)) { + version = atoi(value); + } + return True; +} + +NTSTATUS ads_gpo_get_sysvol_gpt_version(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *filesyspath, + uint32 *sysvol_version) +{ + NTSTATUS status; + const char *path; + struct cli_state *cli; + int fnum; + fstring tok; + static int io_bufsize = 64512; + int read_size = io_bufsize; + char *data = NULL; + off_t start = 0; + off_t nread = 0; + int handle = 0; + const char *local_file; + + *sysvol_version = 0; + + next_token(&filesyspath, tok, "\\", sizeof(tok)); + next_token(&filesyspath, tok, "\\", sizeof(tok)); + + path = talloc_asprintf(mem_ctx, "\\%s\\gpt.ini", filesyspath); + if (path == NULL) { + return NT_STATUS_NO_MEMORY; + } + + local_file = talloc_asprintf(mem_ctx, "%s/%s", lock_path("gpo_cache"), "gpt.ini"); + if (local_file == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* FIXME: walk down the dfs tree instead */ + status = cli_full_connection(&cli, global_myname(), + ads->config.ldap_server_name, + NULL, 0, + "SYSVOL", "A:", + ads->auth.user_name, NULL, ads->auth.password, + CLI_FULL_CONNECTION_USE_KERBEROS, + Undefined, NULL); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + fnum = cli_open(cli, path, O_RDONLY, DENY_NONE); + if (fnum == -1) { + return NT_STATUS_NO_SUCH_FILE; + } + + + data = (char *)SMB_MALLOC(read_size); + if (data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + handle = sys_open(local_file, O_WRONLY|O_CREAT|O_TRUNC, 0644); + + if (handle == -1) { + return NT_STATUS_NO_SUCH_FILE; + } + + while (1) { + + int n = cli_read(cli, fnum, data, nread + start, read_size); + + if (n <= 0) + break; + + if (write(handle, data, n) != n) { + break; + } + + nread += n; + } + + cli_close(cli, fnum); + + if (!pm_process(local_file, do_section, do_parameter)) { + return NT_STATUS_INVALID_PARAMETER; + } + + *sysvol_version = version; + + SAFE_FREE(data); + + cli_shutdown(cli); + + return NT_STATUS_OK; +} + +/* + +perfectly parseable with pm_process() :)) + +[Unicode] +Unicode=yes +[System Access] +MinimumPasswordAge = 1 +MaximumPasswordAge = 42 +MinimumPasswordLength = 7 +PasswordComplexity = 1 +PasswordHistorySize = 24 +LockoutBadCount = 0 +RequireLogonToChangePassword = 0 +ForceLogoffWhenHourExpire = 0 +ClearTextPassword = 0 +[Kerberos Policy] +MaxTicketAge = 10 +MaxRenewAge = 7 +MaxServiceAge = 600 +MaxClockSkew = 5 +TicketValidateClient = 1 +[Version] +signature="$CHICAGO$" +Revision=1 +*/ diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index 44cb43c285e..03dbd71e931 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -3734,7 +3734,7 @@ convert_string_to_sid(struct cli_state *ipc_cli, } if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, - pol, 1, &str, &sids, + pol, 1, &str, NULL, &sids, &types))) { result = False; goto done; @@ -5927,22 +5927,14 @@ smbc_free_context(SMBCCTX *context, void smbc_option_set(SMBCCTX *context, char *option_name, - ...) + void *option_value) { - va_list args; - - va_start(args, option_name); - if (strcmp(option_name, "debug_stderr") == 0) { /* * Log to standard error instead of standard output. - * - * optional parameters: none (it can't be turned off once on) */ context->internal->_debug_stderr = True; } - - va_end(args); } @@ -5991,6 +5983,7 @@ smbc_init_context(SMBCCTX *context) DEBUGLEVEL = context->debug; load_case_tables(); + setup_logging( "libsmbclient", True); setup_logging("libsmbclient", True); if (context->internal->_debug_stderr) { diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c index 8b811b06ead..673671d28db 100644 --- a/source/libsmb/passchange.c +++ b/source/libsmb/passchange.c @@ -24,7 +24,7 @@ Change a password on a remote machine using IPC calls. *************************************************************/ -BOOL remote_password_change(const char *remote_machine, const char *user_name, +NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char *err_str, size_t err_str_len) { @@ -41,7 +41,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if(!resolve_name( remote_machine, &ip, 0x20)) { slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n", remote_machine ); - return False; + return NT_STATUS_UNSUCCESSFUL; } ZERO_STRUCT(cli); @@ -49,7 +49,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) { slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); - return False; + return NT_STATUS_UNSUCCESSFUL; } make_nmb_name(&calling, global_myname() , 0x0); @@ -59,7 +59,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); - return False; + return NT_STATUS_UNSUCCESSFUL; } cli.protocol = PROTOCOL_NT1; @@ -67,8 +67,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if (!cli_negprot(&cli)) { slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } /* Given things like SMB signing, restrict anonymous and the like, @@ -90,7 +91,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, "connect to machine %s: %s\n", remote_machine, cli_errstr(&cli)); cli_shutdown(&cli); - return False; + return result; } pass_must_change = True; @@ -105,8 +106,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } cli_init_creds(&cli, "", "", NULL); @@ -117,8 +119,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } /* Try not to give the password away too easily */ @@ -149,16 +152,18 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, cli_errstr(&cli) ); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } } else { slprintf(err_str, err_str_len-1, "SAMR connection to machine %s failed. Error was %s, " "but LANMAN password changed are disabled\n", nt_errstr(result), remote_machine); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } } @@ -166,7 +171,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, new_passwd, old_passwd))) { /* Great - it all worked! */ cli_shutdown(&cli); - return True; + return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { @@ -175,7 +180,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(&cli); - return False; + return result; } /* OK, that failed, so try again... */ @@ -197,7 +202,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(&cli); - return True; + return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { @@ -207,7 +212,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, "machine %s rejected the (anonymous) password change: Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(&cli); - return False; + return result; } /* We have failed to change the user's password, and we think the server @@ -219,20 +224,21 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(&cli); - return True; + return NT_STATUS_OK; } slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, cli_errstr(&cli) ); + result = cli_nt_error(&cli); cli_shutdown(&cli); - return False; + return result; } else { slprintf(err_str, err_str_len-1, "SAMR connection to machine %s failed. Error was %s, " "but LANMAN password changed are disabled\n", nt_errstr(result), remote_machine); cli_shutdown(&cli); - return False; + return NT_STATUS_UNSUCCESSFUL; } } } diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c index 61c01daa165..57e05dc4bb0 100644 --- a/source/nsswitch/pam_winbind.c +++ b/source/nsswitch/pam_winbind.c @@ -3,12 +3,14 @@ Copyright Andrew Tridgell 2000 Copyright Tim Potter 2000 Copyright Andrew Bartlett 2002 + Copyright Guenther Deschner 2005-2006 largely based on pam_userdb by Cristian Gafton also contains large slabs of code from pam_unix by Elliot Lee (see copyright below for full details) */ +#include "includes.h" #include "pam_winbind.h" /* data tokens */ @@ -27,41 +29,122 @@ static void _pam_log(int err, const char *format, ...) closelog(); } +static void _pam_log_debug(int ctrl, int err, const char *format, ...) +{ + va_list args; + + if (!(ctrl & WINBIND_DEBUG_ARG)) { + return; + } + + va_start(args, format); + openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + static int _pam_parse(int argc, const char **argv) { - int ctrl; + int ctrl = 0; + + load_case_tables(); + + if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) { + return -1; + } + + if (lp_parm_bool(-1, "pam_winbind", "cached_login", False)) { + ctrl |= WINBIND_CACHED_LOGIN; + } + if (lp_parm_bool(-1, "pam_winbind", "krb5_auth", False)) { + ctrl |= WINBIND_KRB5_AUTH; + } + if (lp_parm_const_string(-1, "pam_winbind", "krb5_ccache_type", NULL) != NULL) { + ctrl |= WINBIND_KRB5_CCACHE_TYPE; + } + if ((lp_parm_const_string(-1, "pam_winbind", "require-membership-of", NULL) != NULL) || + (lp_parm_const_string(-1, "pam_winbind", "require_membership_of", NULL) != NULL)) { + ctrl |= WINBIND_REQUIRED_MEMBERSHIP; + } + if (lp_parm_bool(-1, "pam_winbind", "create_homedir", False)) { + ctrl |= WINBIND_CREATE_HOMEDIR; + } + /* step through arguments */ - for (ctrl = 0; argc-- > 0; ++argv) { + for (; argc-- > 0; ++argv) { /* generic options */ - - if (!strcmp(*argv,"debug")) + + if (!StrCaseCmp(*argv, "debug")) ctrl |= WINBIND_DEBUG_ARG; - else if (!strcasecmp(*argv, "use_authtok")) + else if (strequal(*argv, "use_authtok")) ctrl |= WINBIND_USE_AUTHTOK_ARG; - else if (!strcasecmp(*argv, "use_first_pass")) + else if (strequal(*argv, "use_first_pass")) ctrl |= WINBIND_USE_FIRST_PASS_ARG; - else if (!strcasecmp(*argv, "try_first_pass")) + else if (strequal(*argv, "try_first_pass")) ctrl |= WINBIND_TRY_FIRST_PASS_ARG; - else if (!strcasecmp(*argv, "unknown_ok")) + else if (strequal(*argv, "unknown_ok")) ctrl |= WINBIND_UNKNOWN_OK_ARG; - else if (!strncasecmp(*argv, "require_membership_of", strlen("require_membership_of"))) + else if (strnequal(*argv, "require_membership_of", strlen("require_membership_of"))) ctrl |= WINBIND_REQUIRED_MEMBERSHIP; - else if (!strncasecmp(*argv, "require-membership-of", strlen("require-membership-of"))) + else if (strnequal(*argv, "require-membership-of", strlen("require-membership-of"))) ctrl |= WINBIND_REQUIRED_MEMBERSHIP; + else if (strequal(*argv, "krb5_auth")) + ctrl |= WINBIND_KRB5_AUTH; + else if (strnequal(*argv, "krb5_ccache_type", strlen("krb5_ccache_type"))) + ctrl |= WINBIND_KRB5_CCACHE_TYPE; + else if (strequal(*argv, "cached_login")) + ctrl |= WINBIND_CACHED_LOGIN; + else if (strequal(*argv, "create_homedir")) + ctrl |= WINBIND_CREATE_HOMEDIR; else { _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); } + } - return ctrl; -} +}; static void _pam_winbind_cleanup_func(pam_handle_t *pamh, void *data, int error_status) { SAFE_FREE(data); } +static const struct ntstatus_errors { + const char *ntstatus_string; + const char *error_string; +} ntstatus_errors[] = { + {"NT_STATUS_OK", "Success"}, + {"NT_STATUS_BACKUP_CONTROLLER", "No primary Domain Controler available"}, + {"NT_STATUS_PWD_TOO_SHORT", "Password too short"}, + {"NT_STATUS_PWD_TOO_RECENT", "The password of this user is too recent to change"}, + {"NT_STATUS_PWD_HISTORY_CONFLICT", "Password is already in password history"}, + {"NT_STATUS_PASSWORD_EXPIRED", "Your password has expired"}, + {"NT_STATUS_PASSWORD_MUST_CHANGE", "You need to change your password now"}, + {"NT_STATUS_INVALID_WORKSTATION", "You are not allowed to logon from this workstation"}, + {"NT_STATUS_INVALID_LOGON_HOURS", "You are not allowed to logon at this time"}, + {"NT_STATUS_ACCOUNT_EXPIRED", "Your account has expired. Please contact your System administrator"}, /* SCNR */ + {"NT_STATUS_ACCOUNT_DISABLED", "Your account is disabled. Please contact your System administrator"}, /* SCNR */ + {"NT_STATUS_ACCOUNT_LOCKED_OUT", "Your account has been locked. Please contact your System administrator"}, /* SCNR */ + {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", "Invalid Trust Account"}, + {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", "Invalid Trust Account"}, + {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", "Invalid Trust Account"}, + {"NT_STATUS_ACCESS_DENIED", "Access is denied"}, + {NULL, NULL} +}; + +const char *_get_ntstatus_error_string(const char *nt_status_string) +{ + int i; + for (i=0; ntstatus_errors[i].ntstatus_string != NULL; i++) { + if (strequal(ntstatus_errors[i].ntstatus_string, nt_status_string)) { + return ntstatus_errors[i].error_string; + } + } + return NULL; +} + /* --- authentication management functions --- */ /* Attempt a conversation */ @@ -70,16 +153,16 @@ static int converse(pam_handle_t *pamh, int nargs, struct pam_message **message, struct pam_response **response) { - int retval; - struct pam_conv *conv; - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ; - if (retval == PAM_SUCCESS) { - retval = conv->conv(nargs, (const struct pam_message **)message, - response, conv->appdata_ptr); - } + int retval; + struct pam_conv *conv; + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ); + if (retval == PAM_SUCCESS) { + retval = conv->conv(nargs, (const struct pam_message **)message, + response, conv->appdata_ptr); + } - return retval; /* propagate error status */ + return retval; /* propagate error status */ } @@ -103,11 +186,23 @@ static int _make_remark(pam_handle_t * pamh, int type, const char *text) return retval; } -static int pam_winbind_request(enum winbindd_cmd req_type, +static int _make_remark_format(pam_handle_t * pamh, int type, const char *format, ...) +{ + va_list args; + char *var; + + va_start(args, format); + vasprintf(&var, format, args); + va_end(args); + + return _make_remark(pamh, type, var); +} + +static int pam_winbind_request(pam_handle_t * pamh, int ctrl, + enum winbindd_cmd req_type, struct winbindd_request *request, struct winbindd_response *response) { - /* Fill in request and send down pipe */ init_request(request, req_type); @@ -140,19 +235,20 @@ static int pam_winbind_request(enum winbindd_cmd req_type, return PAM_SERVICE_ERR; } } - + return PAM_SUCCESS; } -static int pam_winbind_request_log(enum winbindd_cmd req_type, - struct winbindd_request *request, - struct winbindd_response *response, +static int pam_winbind_request_log(pam_handle_t * pamh, int ctrl, + enum winbindd_cmd req_type, + struct winbindd_request *request, + struct winbindd_response *response, const char *user) { int retval; - retval = pam_winbind_request(req_type, request, response); + retval = pam_winbind_request(pamh, ctrl, req_type, request, response); switch (retval) { case PAM_AUTH_ERR: @@ -168,13 +264,12 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, _pam_log(LOG_WARNING, "user `%s' password expired", user); return retval; case PAM_NEW_AUTHTOK_REQD: - /* password expired */ + /* new password required */ _pam_log(LOG_WARNING, "user `%s' new password required", user); return retval; case PAM_USER_UNKNOWN: /* the user does not exist */ - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_NOTICE, "user `%s' not found", + _pam_log_debug(ctrl, LOG_NOTICE, "user `%s' not found", user); if (ctrl & WINBIND_UNKNOWN_OK_ARG) { return PAM_IGNORE; @@ -191,6 +286,7 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, /* Otherwise, the authentication looked good */ _pam_log(LOG_NOTICE, "user '%s' OK", user); } + return retval; default: /* we don't know anything about this return value */ @@ -201,24 +297,67 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, } /* talk to winbindd */ -static int winbind_auth_request(const char *user, const char *pass, const char *member, int ctrl) +static int winbind_auth_request(pam_handle_t * pamh, + int ctrl, + const char *user, + const char *pass, + const char *member, + const char *cctype, + int process_result) { struct winbindd_request request; struct winbindd_response response; + int ret; ZERO_STRUCT(request); + ZERO_STRUCT(response); strncpy(request.data.auth.user, user, - sizeof(request.data.auth.user)-1); + sizeof(request.data.auth.user)-1); strncpy(request.data.auth.pass, pass, - sizeof(request.data.auth.pass)-1); + sizeof(request.data.auth.pass)-1); + + request.data.auth.krb5_cc_type[0] = '\0'; + request.data.auth.uid = -1; + + request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_CONTACT_TRUSTDOM; + + if (ctrl & WINBIND_KRB5_AUTH) { + + struct passwd *pwd = NULL; + + _pam_log_debug(ctrl, LOG_DEBUG, "enabling krb5 login flag\n"); + + request.flags |= WBFLAG_PAM_KRB5 | WBFLAG_PAM_FALLBACK_AFTER_KRB5; + + pwd = getpwnam(user); + if (pwd == NULL) { + return PAM_USER_UNKNOWN; + } + request.data.auth.uid = pwd->pw_uid; + } - if (member == NULL ) - return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); + if (ctrl & WINBIND_CACHED_LOGIN) { + _pam_log_debug(ctrl, LOG_DEBUG, "enabling cached login flag\n"); + request.flags |= WBFLAG_PAM_CACHED_LOGIN; + } + + if (cctype != NULL) { + strncpy(request.data.auth.krb5_cc_type, cctype, + sizeof(request.data.auth.krb5_cc_type) - 1); + _pam_log_debug(ctrl, LOG_DEBUG, "enabling request for a %s krb5 ccache\n", cctype); + } + + request.data.auth.require_membership_of_sid[0] = '\0'; + + if (member != NULL) { + strncpy(request.data.auth.require_membership_of_sid, member, + sizeof(request.data.auth.require_membership_of_sid)-1); + } /* lookup name? */ - if (!strncmp("S-", member, 2) == 0) { + if ( (member != NULL) && (strncmp("S-", member, 2) != 0) ) { struct winbindd_request sid_request; struct winbindd_response sid_response; @@ -226,55 +365,195 @@ static int winbind_auth_request(const char *user, const char *pass, const char * ZERO_STRUCT(sid_request); ZERO_STRUCT(sid_response); - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_DEBUG, "no sid given, looking up: %s\n", member); + _pam_log_debug(ctrl, LOG_DEBUG, "no sid given, looking up: %s\n", member); /* fortunatly winbindd can handle non-separated names */ - strcpy(sid_request.data.name.name, member); + fstrcpy(sid_request.data.name.name, member); - if (pam_winbind_request_log(WINBINDD_LOOKUPNAME, &sid_request, &sid_response, ctrl, user)) { + if (pam_winbind_request_log(pamh, ctrl, WINBINDD_LOOKUPNAME, &sid_request, &sid_response, user)) { _pam_log(LOG_INFO, "could not lookup name: %s\n", member); return PAM_AUTH_ERR; } member = sid_response.data.sid.sid; + + strncpy(request.data.auth.require_membership_of_sid, member, + sizeof(request.data.auth.require_membership_of_sid)-1); } + + ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_AUTH, &request, &response, user); - strncpy(request.data.auth.require_membership_of_sid, member, - sizeof(request.data.auth.require_membership_of_sid)-1); + if ((ctrl & WINBIND_KRB5_AUTH) && + response.data.auth.krb5ccname[0] != '\0') { + + char var[PATH_MAX]; + + _pam_log_debug(ctrl, LOG_DEBUG, "request returned KRB5CCNAME: %s", + response.data.auth.krb5ccname); - return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); + snprintf(var, sizeof(var), "KRB5CCNAME=%s", response.data.auth.krb5ccname); + + ret = pam_putenv(pamh, var); + if (ret != PAM_SUCCESS) { + _pam_log(LOG_ERR, "failed to set KRB5CCNAME to %s", var); + return ret; + } + } + + if (!process_result) { + return ret; + } + + if (ret) { + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_PASSWORD_EXPIRED"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_PASSWORD_MUST_CHANGE"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_INVALID_WORKSTATION"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_INVALID_LOGON_HOURS"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_ACCOUNT_EXPIRED"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_ACCOUNT_DISABLED"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_ACCOUNT_LOCKED_OUT"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"); + } + + /* handle the case where the auth was ok, but the password must expire right now */ + /* good catch from Ralf Haferkamp: an expiry of "never" is translated to -1 */ + if ((response.data.auth.policy.expire > 0) && + (response.data.auth.info3.pass_last_set_time + response.data.auth.policy.expire < time(NULL))) { + + ret = PAM_AUTHTOK_EXPIRED; + + _pam_log_debug(ctrl, LOG_DEBUG,"Password has expired (Password was last set: %d, " + "the policy says it should expire here %d (now it's: %d)\n", + response.data.auth.info3.pass_last_set_time, + response.data.auth.info3.pass_last_set_time + response.data.auth.policy.expire, + time(NULL)); + + PAM_WB_REMARK_DIRECT_RET(pamh, "NT_STATUS_PASSWORD_EXPIRED"); + + } + + /* warn a user if the password is about to expire soon */ + if ((response.data.auth.policy.expire) && + (response.data.auth.info3.pass_last_set_time + response.data.auth.policy.expire > time(NULL) ) ) { + + int days = response.data.auth.policy.expire / SECONDS_PER_DAY; + if (days <= DAYS_TO_WARN_BEFORE_PWD_EXPIRES) { + _make_remark_format(pamh, PAM_TEXT_INFO, "Your password will expire in %d days", days); + } + } + + if (response.data.auth.info3.user_flgs & LOGON_CACHED_ACCOUNT) { + _make_remark(pamh, PAM_ERROR_MSG, "Logging on using cached account. Network ressources can be unavailable"); + } + + /* save the CIFS homedir for pam_cifs / pam_mount */ + if (response.data.auth.info3.home_dir[0] != '\0') { + char *buf; + + if (!asprintf(&buf, "%s", response.data.auth.info3.home_dir)) { + return PAM_BUF_ERR; + } + + pam_set_data( pamh, PAM_WINBIND_HOMEDIR, (void *)buf, _pam_winbind_cleanup_func); + } + + return ret; } /* talk to winbindd */ -static int winbind_chauthtok_request(const char *user, const char *oldpass, - const char *newpass, int ctrl) +static int winbind_chauthtok_request(pam_handle_t * pamh, + int ctrl, + const char *user, + const char *oldpass, + const char *newpass) { struct winbindd_request request; struct winbindd_response response; + int ret; ZERO_STRUCT(request); + ZERO_STRUCT(response); - if (request.data.chauthtok.user == NULL) return -2; + if (request.data.chauthtok.user == NULL) return -2; strncpy(request.data.chauthtok.user, user, - sizeof(request.data.chauthtok.user) - 1); - - if (oldpass != NULL) { - strncpy(request.data.chauthtok.oldpass, oldpass, - sizeof(request.data.chauthtok.oldpass) - 1); - } else { - request.data.chauthtok.oldpass[0] = '\0'; - } - - if (newpass != NULL) { - strncpy(request.data.chauthtok.newpass, newpass, - sizeof(request.data.chauthtok.newpass) - 1); - } else { - request.data.chauthtok.newpass[0] = '\0'; - } + sizeof(request.data.chauthtok.user) - 1); + + if (oldpass != NULL) { + strncpy(request.data.chauthtok.oldpass, oldpass, + sizeof(request.data.chauthtok.oldpass) - 1); + } else { + request.data.chauthtok.oldpass[0] = '\0'; + } - return pam_winbind_request_log(WINBINDD_PAM_CHAUTHTOK, &request, &response, ctrl, user); + if (newpass != NULL) { + strncpy(request.data.chauthtok.newpass, newpass, + sizeof(request.data.chauthtok.newpass) - 1); + } else { + request.data.chauthtok.newpass[0] = '\0'; + } + + if (ctrl & WINBIND_KRB5_AUTH) { + request.flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM; + } + + ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_CHAUTHTOK, &request, &response, user); + + if (ret == PAM_SUCCESS) { + return ret; + } + + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_BACKUP_CONTROLLER"); + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_ACCESS_DENIED"); + + /* TODO: tell the min pwd length ? */ + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_PWD_TOO_SHORT"); + + /* TODO: tell the minage ? */ + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_PWD_TOO_RECENT"); + + /* TODO: tell the history length ? */ + PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, response, "NT_STATUS_PWD_HISTORY_CONFLICT"); + + if (strequal(response.data.auth.nt_status_string, "NT_STATUS_PASSWORD_RESTRICTION")) { + + /* FIXME: avoid to send multiple PAM messages after another */ + switch (response.data.auth.reject_reason) { + case 0: + break; + case REJECT_REASON_TOO_SHORT: + PAM_WB_REMARK_DIRECT(pamh, "NT_STATUS_PWD_TOO_SHORT"); + break; + case REJECT_REASON_IN_HISTORY: + PAM_WB_REMARK_DIRECT(pamh, "NT_STATUS_PWD_HISTORY_CONFLICT"); + break; + case REJECT_REASON_NOT_COMPLEX: + _make_remark(pamh, PAM_ERROR_MSG, "Password does not meet complexity requirements"); + break; + default: + _pam_log_debug(ctrl, LOG_DEBUG, + "unknown password change reject reason: %d", + response.data.auth.reject_reason); + break; + } + + _make_remark_format(pamh, PAM_ERROR_MSG, + "Your password must be at least %d characters; " + "cannot repeat any of the your previous %d passwords" + "%s. " + "Please type a different password. " + "Type a password which meets these requirements in both text boxes.", + response.data.auth.policy.min_length_password, + response.data.auth.policy.password_history, + (response.data.auth.policy.password_properties & DOMAIN_PASSWORD_COMPLEX) ? + "; must contain capitals, numerals or punctuation; and cannot contain your account or full name" : + ""); + + } + + return ret; } /* @@ -293,21 +572,21 @@ static int valid_user(const char *user) static char *_pam_delete(register char *xx) { - _pam_overwrite(xx); - _pam_drop(xx); - return NULL; + _pam_overwrite(xx); + _pam_drop(xx); + return NULL; } /* * obtain a password from the user */ -static int _winbind_read_password(pam_handle_t * pamh - ,unsigned int ctrl - ,const char *comment - ,const char *prompt1 - ,const char *prompt2 - ,const char **pass) +static int _winbind_read_password(pam_handle_t * pamh, + unsigned int ctrl, + const char *comment, + const char *prompt1, + const char *prompt2, + const char **pass) { int authtok_flag; int retval; @@ -391,16 +670,15 @@ static int _winbind_read_password(pam_handle_t * pamh if (retval == PAM_SUCCESS) { /* a good conversation */ - token = x_strdup(resp[i - replies].resp); + token = SMB_STRDUP(resp[i - replies].resp); if (token != NULL) { if (replies == 2) { - /* verify that password entered correctly */ if (!resp[i - 1].resp - || strcmp(token, resp[i - 1].resp)) { + || StrCaseCmp(token, resp[i - 1].resp)) { _pam_delete(token); /* mistyped */ retval = PAM_AUTHTOK_RECOVER_ERR; - _make_remark(pamh ,PAM_ERROR_MSG, MISTYPED_PASS); + _make_remark(pamh, PAM_ERROR_MSG, MISTYPED_PASS); } } } else { @@ -423,8 +701,7 @@ static int _winbind_read_password(pam_handle_t * pamh } if (retval != PAM_SUCCESS) { - if (on(WINBIND_DEBUG_ARG, ctrl)) - _pam_log(LOG_DEBUG, + _pam_log_debug(ctrl, LOG_DEBUG, "unable to obtain a password"); return retval; } @@ -434,10 +711,8 @@ static int _winbind_read_password(pam_handle_t * pamh retval = pam_set_item(pamh, authtok_flag, token); _pam_delete(token); /* clean it up */ - if (retval != PAM_SUCCESS - || (retval = pam_get_item(pamh, authtok_flag - ,(const void **) &item)) - != PAM_SUCCESS) { + if (retval != PAM_SUCCESS || + (retval = pam_get_item(pamh, authtok_flag, (const void **) &item)) != PAM_SUCCESS) { _pam_log(LOG_CRIT, "error manipulating password"); return retval; @@ -450,92 +725,145 @@ static int _winbind_read_password(pam_handle_t * pamh return PAM_SUCCESS; } +const char *get_conf_item_string(int argc, + const char **argv, + int ctrl, + const char *item, + int flag) +{ + int i = 0; + char *parm = NULL; + const char *parm_opt = NULL; + + if (!(ctrl & flag)) { + goto out; + } + + /* let the pam opt take precedence over the smb.conf option */ + parm_opt = lp_parm_const_string(-1, "pam_winbind", item, NULL); + + for ( i=0; ipw_dir); + + if (directory_exist(pwd->pw_dir, &sbuf)) { + return PAM_SUCCESS; + } + + fstrcpy(create_dir, "/"); + while (next_token((const char **)&pwd->pw_dir, tok, "/", sizeof(tok))) { + + mode_t mode = 0755; + + fstrcat(create_dir, tok); + fstrcat(create_dir, "/"); + + if (!directory_exist(create_dir, &sbuf)) { + if (mkdir(create_dir, mode) != 0) { + _pam_log(LOG_ERR, "could not create dir: %s (%s)", + create_dir, strerror(errno)); + return PAM_SERVICE_ERR; + } + } + } + + if (sys_chown(create_dir, pwd->pw_uid, pwd->pw_gid) != 0) { + _pam_log(LOG_ERR, "failed to chown user homedir: %s (%s)", + create_dir, strerror(errno)); + return PAM_SERVICE_ERR; + } + } + + return PAM_SUCCESS; } + PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) + int argc, const char **argv) { - /* parse arguments */ - int ctrl = _pam_parse(argc, argv); - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_close_session handler"); - return PAM_SUCCESS; + /* parse arguments */ + int ctrl = _pam_parse(argc, argv); + if (ctrl == -1) { + return PAM_SYSTEM_ERR; + } + + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_close_session handler"); + + if (!(flags & PAM_DELETE_CRED)) { + return PAM_SUCCESS; + } + + if (ctrl & WINBIND_KRB5_AUTH) { + + /* destroy the ccache here */ + struct winbindd_request request; + struct winbindd_response response; + const char *user; + const char *ccname = NULL; + struct passwd *pwd = NULL; + + int retval; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + retval = pam_get_user(pamh, &user, "Username: "); + if (retval == PAM_SUCCESS) { + if (user == NULL) { + _pam_log(LOG_ERR, "username was NULL!"); + return PAM_USER_UNKNOWN; + } + if (retval == PAM_SUCCESS) { + _pam_log_debug(ctrl, LOG_DEBUG, "username [%s] obtained", user); + } + } else { + _pam_log_debug(ctrl, LOG_DEBUG, "could not identify user"); + return retval; + } + + ccname = pam_getenv(pamh, "KRB5CCNAME"); + if (ccname == NULL) { + _pam_log_debug(ctrl, LOG_DEBUG, "user has no KRB5CCNAME environment"); + return PAM_BUF_ERR; + } + + fstrcpy(request.data.logoff.user, user); + fstrcpy(request.data.logoff.krb5ccname, ccname); + + pwd = getpwnam(user); + if (pwd == NULL) { + return PAM_USER_UNKNOWN; + } + request.data.logoff.uid = pwd->pw_uid; + + request.flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM; + + return pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_LOGOFF, &request, &response, user); + } + + return PAM_SUCCESS; } -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, - int argc, const char **argv) +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t * pamh, int flags, + int argc, const char **argv) { unsigned int lctrl; int retval; - unsigned int ctrl = _pam_parse(argc, argv); + unsigned int ctrl; /* */ const char *user; - const char *member = NULL; char *pass_old, *pass_new; /* */ - char *Announce; + fstring Announce; int retry = 0; + ctrl = _pam_parse(argc, argv); + if (ctrl == -1) { + return PAM_SYSTEM_ERR; + } + + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_chauthtok"); + /* * First get the name of a user */ @@ -659,13 +1111,13 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, _pam_log(LOG_ERR, "username was NULL!"); return PAM_USER_UNKNOWN; } - if (retval == PAM_SUCCESS && on(WINBIND_DEBUG_ARG, ctrl)) - _pam_log(LOG_DEBUG, "username [%s] obtained", + if (retval == PAM_SUCCESS) { + _pam_log_debug(ctrl, LOG_DEBUG, "username [%s] obtained", user); + } } else { - if (on(WINBIND_DEBUG_ARG, ctrl)) - _pam_log(LOG_DEBUG, - "password - could not identify user"); + _pam_log_debug(ctrl, LOG_DEBUG, + "password - could not identify user"); return retval; } @@ -678,33 +1130,24 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, /* instruct user what is happening */ #define greeting "Changing password for " - Announce = (char *) malloc(sizeof(greeting) + strlen(user)); - if (Announce == NULL) { - _pam_log(LOG_CRIT, - "password - out of memory"); - return PAM_BUF_ERR; - } - (void) strcpy(Announce, greeting); - (void) strcpy(Announce + sizeof(greeting) - 1, user); + fstrcpy(Announce, greeting); + fstrcat(Announce, user); #undef greeting lctrl = ctrl | WINBIND__OLD_PASSWORD; - retval = _winbind_read_password(pamh, lctrl - ,Announce - ,"(current) NT password: " - ,NULL - ,(const char **) &pass_old); - free(Announce); - + retval = _winbind_read_password(pamh, lctrl, + Announce, + "(current) NT password: ", + NULL, + (const char **) &pass_old); if (retval != PAM_SUCCESS) { - _pam_log(LOG_NOTICE - ,"password - (old) token not obtained"); + _pam_log(LOG_NOTICE, "password - (old) token not obtained"); return retval; } /* verify that this is the password for this user */ - retval = winbind_auth_request(user, pass_old, member, ctrl); - + retval = winbind_auth_request(pamh, ctrl, user, pass_old, NULL, NULL, False); + if (retval != PAM_ACCT_EXPIRED && retval != PAM_AUTHTOK_EXPIRED && retval != PAM_NEW_AUTHTOK_REQD @@ -716,8 +1159,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { - _pam_log(LOG_CRIT, - "failed to set PAM_OLDAUTHTOK"); + _pam_log(LOG_CRIT, "failed to set PAM_OLDAUTHTOK"); } } else if (flags & PAM_UPDATE_AUTHTOK) { @@ -729,8 +1171,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * get the old token back. */ - retval = pam_get_item(pamh, PAM_OLDAUTHTOK - ,(const void **) &pass_old); + retval = pam_get_item(pamh, PAM_OLDAUTHTOK, + (const void **) &pass_old); if (retval != PAM_SUCCESS) { _pam_log(LOG_NOTICE, "user not authenticated"); @@ -750,17 +1192,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * password -- needed for pluggable password strength checking */ - retval = _winbind_read_password(pamh, lctrl - ,NULL - ,"Enter new NT password: " - ,"Retype new NT password: " - ,(const char **) &pass_new); + retval = _winbind_read_password(pamh, lctrl, + NULL, + "Enter new NT password: ", + "Retype new NT password: ", + (const char **) &pass_new); if (retval != PAM_SUCCESS) { - if (on(WINBIND_DEBUG_ARG, ctrl)) { - _pam_log(LOG_ALERT - ,"password - new password not obtained"); - } + _pam_log_debug(ctrl, LOG_ALERT + ,"password - new password not obtained"); pass_old = NULL;/* tidy up */ return retval; } @@ -781,14 +1221,30 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * rebuild the password database file. */ - retval = winbind_chauthtok_request(user, pass_old, pass_new, ctrl); - _pam_overwrite(pass_new); - _pam_overwrite(pass_old); - pass_old = pass_new = NULL; + retval = winbind_chauthtok_request(pamh, ctrl, user, pass_old, pass_new); + if (retval) { + _pam_overwrite(pass_new); + _pam_overwrite(pass_old); + pass_old = pass_new = NULL; + return retval; + } + + /* just in case we need krb5 creds after a password change over msrpc */ + + if (ctrl & WINBIND_KRB5_AUTH) { + + const char *member = get_member_from_config(argc, argv, ctrl); + const char *cctype = get_krb5_cc_type_from_config(argc, argv, ctrl); + + retval = winbind_auth_request(pamh, ctrl, user, pass_new, member, cctype, False); + _pam_overwrite(pass_new); + _pam_overwrite(pass_old); + pass_old = pass_new = NULL; + } } else { retval = PAM_SERVICE_ERR; } - + return retval; } @@ -797,13 +1253,13 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, /* static module data */ struct pam_module _pam_winbind_modstruct = { - MODULE_NAME, - pam_sm_authenticate, - pam_sm_setcred, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - pam_sm_chauthtok + MODULE_NAME, + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok }; #endif @@ -812,6 +1268,7 @@ struct pam_module _pam_winbind_modstruct = { * Copyright (c) Andrew Tridgell 2000 * Copyright (c) Tim Potter 2000 * Copyright (c) Andrew Bartlettt 2002 + * Copyright (c) Guenther Deschner 2005-2006 * Copyright (c) Jan Rêkorajski 1999. * Copyright (c) Andrew G. Morgan 1996-8. * Copyright (c) Alex O. Yuriev, 1996. diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h index 86ba9772879..1e38269e0ee 100644 --- a/source/nsswitch/pam_winbind.h +++ b/source/nsswitch/pam_winbind.h @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -83,8 +84,10 @@ do { \ #define WINBIND_USE_FIRST_PASS_ARG (1<<4) #define WINBIND__OLD_PASSWORD (1<<5) #define WINBIND_REQUIRED_MEMBERSHIP (1<<6) - -#define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD" +#define WINBIND_KRB5_AUTH (1<<7) +#define WINBIND_KRB5_CCACHE_TYPE (1<<8) +#define WINBIND_CACHED_LOGIN (1<<9) +#define WINBIND_CREATE_HOMEDIR (1<<10) /* * here is the string to inform the user that the new passwords they @@ -96,4 +99,53 @@ do { \ #define on(x, y) (x & y) #define off(x, y) (!(x & y)) +#define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD" +#define PAM_WINBIND_HOMEDIR "PAM_WINBIND_HOMEDIR" + +#define SECONDS_PER_DAY 86400 + +#define DAYS_TO_WARN_BEFORE_PWD_EXPIRES 5 + #include "winbind_client.h" + +#define PAM_WB_REMARK_DIRECT(h,x)\ +{\ + const char *error_string = NULL; \ + error_string = _get_ntstatus_error_string(x);\ + if (error_string != NULL) {\ + _make_remark(h, PAM_ERROR_MSG, error_string);\ + } else {\ + _make_remark(h, PAM_ERROR_MSG, x);\ + };\ +}; + +#define PAM_WB_REMARK_DIRECT_RET(h,x)\ +{\ + const char *error_string = NULL; \ + error_string = _get_ntstatus_error_string(x);\ + if (error_string != NULL) {\ + _make_remark(h, PAM_ERROR_MSG, error_string);\ + return ret;\ + };\ + _make_remark(h, PAM_ERROR_MSG, x);\ + return ret;\ +}; + +#define PAM_WB_REMARK_CHECK_RESPONSE_RET(h,x,y)\ +{\ + const char *ntstatus = x.data.auth.nt_status_string; \ + const char *error_string = NULL; \ + if (strequal(ntstatus,y)) {\ + error_string = _get_ntstatus_error_string(y);\ + if (error_string != NULL) {\ + _make_remark(h, PAM_ERROR_MSG, error_string);\ + return ret;\ + };\ + if (x.data.auth.error_string[0] != '\0') {\ + _make_remark(h, PAM_ERROR_MSG, x.data.auth.error_string);\ + return ret;\ + };\ + _make_remark(h, PAM_ERROR_MSG, y);\ + return ret;\ + };\ +}; diff --git a/source/nsswitch/wb_client.c b/source/nsswitch/wb_client.c index fcab76b033a..ff0f15a1224 100644 --- a/source/nsswitch/wb_client.c +++ b/source/nsswitch/wb_client.c @@ -247,7 +247,7 @@ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid) return (result == NSS_STATUS_SUCCESS); } -BOOL winbind_allocate_rid(uint32 *rid) +BOOL winbind_allocate_uid(uid_t *uid) { struct winbindd_request request; struct winbindd_response response; @@ -260,18 +260,19 @@ BOOL winbind_allocate_rid(uint32 *rid) /* Make request */ - result = winbindd_request_response(WINBINDD_ALLOCATE_RID, &request, &response); + result = winbindd_request_response(WINBINDD_ALLOCATE_UID, + &request, &response); if (result != NSS_STATUS_SUCCESS) return False; /* Copy out result */ - *rid = response.data.rid; + *uid = response.data.uid; return True; } -BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid) +BOOL winbind_allocate_gid(gid_t *gid) { struct winbindd_request request; struct winbindd_response response; @@ -284,15 +285,14 @@ BOOL winbind_allocate_rid_and_gid(uint32 *rid, gid_t *gid) /* Make request */ - result = winbindd_request_response(WINBINDD_ALLOCATE_RID_AND_GID, &request, - &response); + result = winbindd_request_response(WINBINDD_ALLOCATE_GID, + &request, &response); if (result != NSS_STATUS_SUCCESS) return False; /* Copy out result */ - *rid = response.data.rid_and_gid.rid; - *gid = response.data.rid_and_gid.gid; + *gid = response.data.gid; return True; } diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index 793a05f1790..571a1b3e19f 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -199,7 +199,7 @@ static BOOL wbinfo_get_userdomgroups(const char *user_sid) return False; if (response.data.num_entries != 0) - d_printf("%s", (char *)response.extra_data); + printf("%s", (char *)response.extra_data); SAFE_FREE(response.extra_data); @@ -260,15 +260,19 @@ static BOOL wbinfo_wins_byip(char *ip) /* List trusted domains */ -static BOOL wbinfo_list_domains(void) +static BOOL wbinfo_list_domains(BOOL list_all_domains) { + struct winbindd_request request; struct winbindd_response response; + ZERO_STRUCT(request); ZERO_STRUCT(response); /* Send request */ - if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, NULL, &response) != + request.data.list_all_domains = list_all_domains; + + if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, &request, &response) != NSS_STATUS_SUCCESS) return False; @@ -510,14 +514,26 @@ static BOOL wbinfo_sid_to_gid(char *sid) return True; } -static BOOL wbinfo_allocate_rid(void) +static BOOL wbinfo_allocate_uid(void) { - uint32 rid; + uid_t uid; - if (!winbind_allocate_rid(&rid)) + if (!winbind_allocate_uid(&uid)) return False; - d_printf("New rid: %d\n", rid); + d_printf("New uid: %d\n", uid); + + return True; +} + +static BOOL wbinfo_allocate_gid(void) +{ + gid_t gid; + + if (!winbind_allocate_gid(&gid)) + return False; + + d_printf("New gid: %d\n", gid); return True; } @@ -577,6 +593,67 @@ static BOOL wbinfo_lookupname(char *name) /* Authenticate a user with a plaintext password */ +static BOOL wbinfo_auth_krb5(char *username, const char *cctype, uint32 flags) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + char *p; + + /* Send off request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + p = strchr(username, '%'); + + if (p) { + *p = 0; + fstrcpy(request.data.auth.user, username); + fstrcpy(request.data.auth.pass, p + 1); + *p = '%'; + } else + fstrcpy(request.data.auth.user, username); + + request.flags = flags; + + fstrcpy(request.data.auth.krb5_cc_type, cctype); + + request.data.auth.uid = geteuid(); + + result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); + + /* Display response */ + + d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", + username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype); + + if (response.data.auth.nt_status) + d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", + response.data.auth.nt_status_string, + response.data.auth.nt_status, + response.data.auth.error_string); + + if (result == NSS_STATUS_SUCCESS) { + + if (request.flags & WBFLAG_PAM_INFO3_TEXT) { + if (response.data.auth.info3.user_flgs & LOGON_CACHED_ACCOUNT) { + d_printf("user_flgs: LOGON_CACHED_ACCOUNT\n"); + } + } + + if (response.data.auth.krb5ccname[0] != '\0') { + d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname); + } else { + d_printf("no credentials cached\n"); + } + } + + return result == NSS_STATUS_SUCCESS; +} + +/* Authenticate a user with a plaintext password */ + static BOOL wbinfo_auth(char *username) { struct winbindd_request request; @@ -968,7 +1045,10 @@ enum { OPT_GETDCNAME, OPT_USERDOMGROUPS, OPT_USERSIDS, - OPT_SEPARATOR + OPT_ALLOCATE_UID, + OPT_ALLOCATE_GID, + OPT_SEPARATOR, + OPT_LIST_ALL_DOMAINS }; int main(int argc, char **argv) @@ -997,9 +1077,13 @@ int main(int argc, char **argv) { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" }, { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" }, { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" }, - { "allocate-rid", 'A', POPT_ARG_NONE, 0, 'A', "Get a new RID out of idmap" }, + { "allocate-uid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_UID, + "Get a new UID out of idmap" }, + { "allocate-gid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_GID, + "Get a new GID out of idmap" }, { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" }, { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" }, + { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" }, { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" }, { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" }, { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" }, @@ -1015,6 +1099,11 @@ int main(int argc, char **argv) { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" }, #ifdef WITH_FAKE_KASERVER { "klog", 'k', POPT_ARG_STRING, &string_arg, 'k', "set an AFS token from winbind", "user%password" }, +#endif +#ifdef HAVE_KRB5 + { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" }, + /* destroys wbinfo --help output */ + /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */ #endif { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL }, POPT_COMMON_VERSION @@ -1120,9 +1209,15 @@ int main(int argc, char **argv) goto done; } break; - case 'A': - if (!wbinfo_allocate_rid()) { - d_fprintf(stderr, "Could not allocate a RID\n"); + case OPT_ALLOCATE_UID: + if (!wbinfo_allocate_uid()) { + d_fprintf(stderr, "Could not allocate a uid\n"); + goto done; + } + break; + case OPT_ALLOCATE_GID: + if (!wbinfo_allocate_gid()) { + d_fprintf(stderr, "Could not allocate a gid\n"); goto done; } break; @@ -1133,7 +1228,7 @@ int main(int argc, char **argv) } break; case 'm': - if (!wbinfo_list_domains()) { + if (!wbinfo_list_domains(False)) { d_fprintf(stderr, "Could not list trusted domains\n"); goto done; } @@ -1190,6 +1285,38 @@ int main(int argc, char **argv) goto done; break; } + case 'K': { + BOOL got_error = False; + uint32 flags = WBFLAG_PAM_KRB5 | + WBFLAG_PAM_CACHED_LOGIN | + WBFLAG_PAM_FALLBACK_AFTER_KRB5 | + WBFLAG_PAM_INFO3_TEXT; + fstring tok; + int i; + const char *arg[] = { string_arg, NULL }; + const char *cctypes[] = { "FILE", + "KCM", + "KCM:0", + "Garbage", + NULL, + "0"}; + + while (next_token(arg, tok, LIST_SEP, sizeof(tok))) { + + for (i=0; i < ARRAY_SIZE(cctypes); i++) { + if (!wbinfo_auth_krb5(tok, cctypes[i], flags)) { + d_fprintf(stderr, "Could not authenticate user [%s] with " + "Kerberos (ccache: %s)\n", tok, cctypes[i]); + got_error = True; + } + } + } + + if (got_error) + goto done; + + break; + } case 'k': if (!wbinfo_klog(string_arg)) { d_fprintf(stderr, "Could not klog user\n"); @@ -1198,7 +1325,7 @@ int main(int argc, char **argv) break; case 'p': if (!wbinfo_ping()) { - d_fprintf(stderr, "Could not ping winbindd!\n"); + d_fprintf(stderr, "could not ping winbindd!\n"); goto done; } break; @@ -1223,6 +1350,10 @@ int main(int argc, char **argv) d_printf("%c\n", sep); break; } + case OPT_LIST_ALL_DOMAINS: + if (!wbinfo_list_domains(True)) { + goto done; + } /* generic configuration options */ case OPT_DOMAIN_NAME: break; diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index bbcf2b5e887..4a269bac17a 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -120,7 +120,7 @@ static void winbindd_status(void) if (DEBUGLEVEL >= 2 && winbindd_num_clients()) { DEBUG(2, ("\tclient list:\n")); for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) { - DEBUG(2, ("\t\tpid %lu, sock %d\n", + DEBUGADD(2, ("\t\tpid %lu, sock %d\n", (unsigned long)tmp->pid, tmp->sock)); } } @@ -250,6 +250,7 @@ static struct winbindd_dispatch_table { { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" }, { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" }, { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" }, + { WINBINDD_PAM_LOGOFF, winbindd_pam_logoff, "PAM_LOGOFF" }, /* Enumeration functions */ @@ -270,9 +271,8 @@ static struct winbindd_dispatch_table { { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" }, { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" }, { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" }, - { WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" }, - { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_allocate_rid_and_gid, - "ALLOCATE_RID_AND_GID" }, + { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" }, + { WINBINDD_ALLOCATE_GID, winbindd_allocate_uid, "ALLOCATE_GID" }, /* Miscellaneous */ @@ -1062,7 +1062,11 @@ int main(int argc, char **argv) as to SIGHUP signal */ message_register(MSG_SMB_CONF_UPDATED, msg_reload_services); message_register(MSG_SHUTDOWN, msg_shutdown); - + + /* Handle online/offline messages. */ + message_register(MSG_WINBIND_OFFLINE,winbind_msg_offline); + message_register(MSG_WINBIND_ONLINE,winbind_msg_online); + poptFreeContext(pc); netsamlogon_cache_init(); /* Non-critical */ diff --git a/source/nsswitch/winbindd.h b/source/nsswitch/winbindd.h index 00a02330559..e81102571c9 100644 --- a/source/nsswitch/winbindd.h +++ b/source/nsswitch/winbindd.h @@ -143,7 +143,9 @@ struct winbindd_child { struct winbindd_domain *domain; pstring logfilename; + TALLOC_CTX *mem_ctx; struct fd_event event; + struct timed_event *timed_event; struct winbindd_async_request *requests; }; @@ -157,7 +159,8 @@ struct winbindd_domain { BOOL native_mode; /* is this a win2k domain in native mode ? */ BOOL active_directory; /* is this a win2k active directory ? */ BOOL primary; /* is this our primary domain ? */ - BOOL internal; /* BUILTIN and member SAM */ + BOOL internal; /* BUILTIN and member SAM */ + BOOL online; /* is this domain available ? */ /* Lookup methods for this domain (LDAP or RPC) */ struct winbindd_methods *methods; @@ -268,6 +271,16 @@ struct winbindd_methods { /* return the current global sequence number */ NTSTATUS (*sequence_number)(struct winbindd_domain *domain, uint32 *seq); + /* return the lockout policy */ + NTSTATUS (*lockout_policy)(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_12 *lockout_policy); + + /* return the lockout policy */ + NTSTATUS (*password_policy)(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_1 *password_policy); + /* enumerate trusted domains */ NTSTATUS (*trusted_domains)(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, @@ -305,7 +318,7 @@ struct winbindd_idmap_methods { #define WINBINDD_ESTABLISH_LOOP 30 #define WINBINDD_RESCAN_FREQ 300 - +#define WINBINDD_PAM_AUTH_KRB5_RENEW_TIME 2592000 /* one month */ #define DOM_SEQUENCE_NONE ((uint32)-1) #endif /* _WINBINDD_H */ diff --git a/source/nsswitch/winbindd_ads.c b/source/nsswitch/winbindd_ads.c index 29129e823a2..a8663650423 100644 --- a/source/nsswitch/winbindd_ads.c +++ b/source/nsswitch/winbindd_ads.c @@ -102,6 +102,8 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) ads->auth.realm = SMB_STRDUP( lp_realm() ); } + ads->auth.renewable = 1; + status = ads_connect(ads); if (!ADS_ERR_OK(status) || !ads->config.realm) { extern struct winbindd_methods msrpc_methods, cache_methods; @@ -206,8 +208,10 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, name = ads_pull_username(ads, mem_ctx, msg); gecos = ads_pull_string(ads, mem_ctx, msg, "name"); if (use_nss_info("sfu")) { - homedir = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_homedir_attr); - shell = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_shell_attr); + homedir = ads_pull_string(ads, mem_ctx, msg, + ads->schema.sfu_homedir_attr); + shell = ads_pull_string(ads, mem_ctx, msg, + ads->schema.sfu_shell_attr); } if (!ads_pull_sid(ads, msg, "objectSid", @@ -474,8 +478,10 @@ static NTSTATUS query_user(struct winbindd_domain *domain, info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); if (use_nss_info("sfu")) { - info->homedir = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_homedir_attr); - info->shell = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_shell_attr); + info->homedir = ads_pull_string(ads, mem_ctx, msg, + ads->schema.sfu_homedir_attr); + info->shell = ads_pull_string(ads, mem_ctx, msg, + ads->schema.sfu_shell_attr); } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { @@ -872,8 +878,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, struct ds_domain_trust *domains = NULL; int count = 0; int i; - /* i think we only need our forest and downlevel trusted domains */ - uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND; + uint32 flags = DS_DOMAIN_DIRECT_OUTBOUND; struct rpc_pipe_client *cli; DEBUG(3,("ads: trusted_domains\n")); @@ -946,6 +951,8 @@ struct winbindd_methods ads_methods = { msrpc_lookup_useraliases, lookup_groupmem, sequence_number, + msrpc_lockout_policy, + msrpc_password_policy, trusted_domains, }; diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c index 9ecfb1ff6ed..28633757c09 100644 --- a/source/nsswitch/winbindd_cache.c +++ b/source/nsswitch/winbindd_cache.c @@ -6,7 +6,7 @@ Copyright (C) Andrew Tridgell 2001 Copyright (C) Gerald Carter 2003 Copyright (C) Volker Lendecke 2005 - + Copyright (C) Guenther Deschner 2005 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 @@ -29,6 +29,12 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +/* Global online/offline state - False when online. winbindd starts up online + and sets this to true if the first query fails and there's an entry in + the cache tdb telling us to stay offline. */ + +static BOOL global_winbindd_offline_state; + struct winbind_cache { TDB_CONTEXT *tdb; }; @@ -44,29 +50,6 @@ struct cache_entry { static struct winbind_cache *wcache; -/* flush the cache */ -void wcache_flush_cache(void) -{ - extern BOOL opt_nocache; - - if (!wcache) - return; - if (wcache->tdb) { - tdb_close(wcache->tdb); - wcache->tdb = NULL; - } - if (opt_nocache) - return; - - wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000, - TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600); - - if (!wcache->tdb) { - DEBUG(0,("Failed to open winbindd_cache.tdb!\n")); - } - DEBUG(10,("wcache_flush_cache success\n")); -} - void winbindd_check_cache_size(time_t t) { static time_t last_check_time; @@ -187,6 +170,22 @@ static uint32 centry_uint32(struct cache_entry *centry) return ret; } +/* + pull a uint16 from a cache entry +*/ +static uint16 centry_uint16(struct cache_entry *centry) +{ + uint16 ret; + if (centry->len - centry->ofs < 2) { + DEBUG(0,("centry corruption? needed 2 bytes, have %d\n", + centry->len - centry->ofs)); + smb_panic("centry_uint16"); + } + ret = CVAL(centry->data, centry->ofs); + centry->ofs += 2; + return ret; +} + /* pull a uint8 from a cache entry */ @@ -203,6 +202,40 @@ static uint8 centry_uint8(struct cache_entry *centry) return ret; } +/* + pull a NTTIME from a cache entry +*/ +static NTTIME centry_nttime(struct cache_entry *centry) +{ + NTTIME ret; + if (centry->len - centry->ofs < 8) { + DEBUG(0,("centry corruption? needed 8 bytes, have %d\n", + centry->len - centry->ofs)); + smb_panic("centry_nttime"); + } + ret.low = IVAL(centry->data, centry->ofs); + centry->ofs += 4; + ret.high = IVAL(centry->data, centry->ofs); + centry->ofs += 4; + return ret; +} + +/* + pull a time_t from a cache entry +*/ +static time_t centry_time(struct cache_entry *centry) +{ + time_t ret; + if (centry->len - centry->ofs < sizeof(time_t)) { + DEBUG(0,("centry corruption? needed %d bytes, have %d\n", + sizeof(time_t), centry->len - centry->ofs)); + smb_panic("centry_time"); + } + ret = IVAL(centry->data, centry->ofs); /* FIXME: correct ? */ + centry->ofs += sizeof(time_t); + return ret; +} + /* pull a string from a cache entry, using the supplied talloc context */ @@ -403,10 +436,28 @@ done: */ static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry) { + /* If we've been told to be offline - stay in that state... */ + if (lp_winbind_offline_logon() && global_winbindd_offline_state) { + DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n", + keystr, domain->name )); + return False; + } + + /* when the domain is offline and we havent checked in the last 30 + * seconds if it has become online again, return the cached entry. + * This deals with transient offline states... */ + + if (!domain->online && + !NT_STATUS_IS_OK(check_negative_conn_cache(domain->name, domain->dcname))) { + DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n", + keystr, domain->name )); + return False; + } + /* if the server is OK and our cache entry came from when it was down then the entry is invalid */ - if (domain->sequence_number != DOM_SEQUENCE_NONE && - centry->sequence_number == DOM_SEQUENCE_NONE) { + if ((domain->sequence_number != DOM_SEQUENCE_NONE) && + (centry->sequence_number == DOM_SEQUENCE_NONE)) { DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n", keystr, domain->name )); return True; @@ -428,35 +479,17 @@ static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, s return True; } -/* - fetch an entry from the cache, with a varargs key. auto-fetch the sequence - number and return status -*/ -static struct cache_entry *wcache_fetch(struct winbind_cache *cache, - struct winbindd_domain *domain, - const char *format, ...) PRINTF_ATTRIBUTE(3,4); -static struct cache_entry *wcache_fetch(struct winbind_cache *cache, - struct winbindd_domain *domain, - const char *format, ...) +static struct cache_entry *wcache_fetch_raw(char *kstr) { - va_list ap; - char *kstr; TDB_DATA data; struct cache_entry *centry; TDB_DATA key; - refresh_sequence_number(domain, False); - - va_start(ap, format); - smb_xvasprintf(&kstr, format, ap); - va_end(ap); - key.dptr = kstr; key.dsize = strlen(kstr); data = tdb_fetch(wcache->tdb, key); if (!data.dptr) { /* a cache miss */ - free(kstr); return NULL; } @@ -467,16 +500,44 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache, if (centry->len < 8) { /* huh? corrupt cache? */ - DEBUG(10,("wcache_fetch: Corrupt cache for key %s domain %s (len < 8) ?\n", - kstr, domain->name )); + DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr)); centry_free(centry); - free(kstr); return NULL; } centry->status = NT_STATUS(centry_uint32(centry)); centry->sequence_number = centry_uint32(centry); + return centry; +} + +/* + fetch an entry from the cache, with a varargs key. auto-fetch the sequence + number and return status +*/ +static struct cache_entry *wcache_fetch(struct winbind_cache *cache, + struct winbindd_domain *domain, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); +static struct cache_entry *wcache_fetch(struct winbind_cache *cache, + struct winbindd_domain *domain, + const char *format, ...) +{ + va_list ap; + char *kstr; + struct cache_entry *centry; + + refresh_sequence_number(domain, False); + + va_start(ap, format); + smb_xvasprintf(&kstr, format, ap); + va_end(ap); + + centry = wcache_fetch_raw(kstr); + if (centry == NULL) { + free(kstr); + return NULL; + } + if (centry_expired(domain, kstr, centry)) { DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n", @@ -521,6 +582,16 @@ static void centry_put_uint32(struct cache_entry *centry, uint32 v) centry->ofs += 4; } +/* + push a uint16 into a centry +*/ +static void centry_put_uint16(struct cache_entry *centry, uint16 v) +{ + centry_expand(centry, 2); + SIVAL(centry->data, centry->ofs, v); + centry->ofs += 2; +} + /* push a uint8 into a centry */ @@ -562,6 +633,28 @@ static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) centry_put_string(centry, sid_to_string(sid_string, sid)); } +/* + push a NTTIME into a centry +*/ +static void centry_put_nttime(struct cache_entry *centry, NTTIME nt) +{ + centry_expand(centry, 8); + SIVAL(centry->data, centry->ofs, nt.low); + centry->ofs += 4; + SIVAL(centry->data, centry->ofs, nt.high); + centry->ofs += 4; +} + +/* + push a time_t into a centry +*/ +static void centry_put_time(struct cache_entry *centry, time_t t) +{ + centry_expand(centry, sizeof(time_t)); + SIVAL(centry->data, centry->ofs, t); /* FIXME: is this correct ?? */ + centry->ofs += sizeof(time_t); +} + /* start a centry for output. When finished, call centry_end() */ @@ -666,6 +759,129 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI centry_free(centry); } +static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy) +{ + struct cache_entry *centry; + + centry = centry_start(domain, status); + if (!centry) + return; + + centry_put_nttime(centry, lockout_policy->duration); + centry_put_nttime(centry, lockout_policy->reset_count); + centry_put_uint16(centry, lockout_policy->bad_attempt_lockout); + + centry_end(centry, "LOC_POL/%s", domain->name); + + DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name)); + + centry_free(centry); +} + +static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *password_policy) +{ + struct cache_entry *centry; + + centry = centry_start(domain, status); + if (!centry) + return; + + centry_put_uint16(centry, password_policy->min_length_password); + centry_put_uint16(centry, password_policy->password_history); + centry_put_uint32(centry, password_policy->password_properties); + centry_put_nttime(centry, password_policy->expire); + centry_put_nttime(centry, password_policy->min_passwordage); + + centry_end(centry, "PWD_POL/%s", domain->name); + + DEBUG(10,("wcache_save_password_policy: %s\n", domain->name)); + + centry_free(centry); +} + +NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid) +{ + struct winbind_cache *cache = get_cache(domain); + TDB_DATA data; + fstring key_str; + + if (!cache->tdb) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid)); + + data = tdb_fetch(cache->tdb, make_tdb_data(key_str, strlen(key_str))); + if (!data.dptr) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + return NT_STATUS_OK; +} + +/* Lookup creds for a SID */ +NTSTATUS wcache_get_creds(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + const uint8 **cached_nt_pass) +{ + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS status; + time_t t; + + if (!cache->tdb) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid)); + + if (!centry) { + DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n", + sid_string_static(sid))); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + t = centry_time(centry); + *cached_nt_pass = (const uint8 *)centry_string(centry, mem_ctx); + + dump_data(10, (const char *)cached_nt_pass, NT_HASH_LEN); + status = centry->status; + + DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status %s\n", + sid_string_static(sid), get_friendly_nt_error_msg(status) )); + + centry_free(centry); + return status; +} + +NTSTATUS wcache_save_creds(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + const uint8 nt_pass[NT_HASH_LEN]) +{ + struct cache_entry *centry; + fstring sid_string; + NTSTATUS status = NT_STATUS_OK; /* ??? */ + + centry = centry_start(domain, status); + if (!centry) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + dump_data(100, (const char *)nt_pass, NT_HASH_LEN); + + centry_put_time(centry, time(NULL)); + centry_put_string(centry, (const char *)nt_pass); + centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid)); + + DEBUG(10,("wcache_save_creds: %s\n", sid_string)); + + centry_free(centry); + + return NT_STATUS_OK; +} + /* Query display info. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, @@ -991,7 +1207,9 @@ do_query: status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type); /* and save it */ - wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type); + if (domain->online || !is_null_sid(sid)) { + wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type); + } if (NT_STATUS_IS_OK(status)) { strupper_m(CONST_DISCARD(char *,domain_name)); @@ -1390,7 +1608,9 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) return NT_STATUS_OK; } -/* enumerate trusted domains */ +/* enumerate trusted domains + * (we need to have the list of trustdoms in the cache when we go offline) - + * Guenther */ static NTSTATUS trusted_domains(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_domains, @@ -1398,16 +1618,184 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, char ***alt_names, DOM_SID **dom_sids) { - get_cache(domain); + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS status; + int i; + + if (!cache->tdb) + goto do_query; + + centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name); + + if (!centry) { + goto do_query; + } + + *num_domains = centry_uint32(centry); + + (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains); + (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains); + (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains); + + if (! (*dom_sids) || ! (*names) || ! (*alt_names)) { + smb_panic("trusted_domains out of memory"); + } + + for (i=0; i<(*num_domains); i++) { + (*names)[i] = centry_string(centry, mem_ctx); + (*alt_names)[i] = centry_string(centry, mem_ctx); + centry_sid(centry, &(*dom_sids)[i]); + } + status = centry->status; + + DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s status %s\n", + domain->name, get_friendly_nt_error_msg(status) )); + + centry_free(centry); + return status; + +do_query: + (*num_domains) = 0; + (*dom_sids) = NULL; + (*names) = NULL; + (*alt_names) = NULL; + + /* Return status value returned by seq number check */ + + if (!NT_STATUS_IS_OK(domain->last_status)) + return domain->last_status; + DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n", domain->name )); + + status = domain->backend->trusted_domains(domain, mem_ctx, num_domains, + names, alt_names, dom_sids); + + /* and save it */ + refresh_sequence_number(domain, False); + + centry = centry_start(domain, status); + if (!centry) + goto skip_save; + + centry_put_uint32(centry, *num_domains); + + for (i=0; i<(*num_domains); i++) { + centry_put_string(centry, (*names)[i]); + centry_put_string(centry, (*alt_names)[i]); + centry_put_sid(centry, &(*dom_sids)[i]); + } + + centry_end(centry, "TRUSTDOMS/%s", domain->name); + + centry_free(centry); + +skip_save: + return status; +} + +/* get lockout policy */ +static NTSTATUS lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_12 *lockout_policy){ + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS status; + + if (!cache->tdb) + goto do_query; + + centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name); + + if (!centry) + goto do_query; + + lockout_policy->duration = centry_nttime(centry); + lockout_policy->reset_count = centry_nttime(centry); + lockout_policy->bad_attempt_lockout = centry_uint16(centry); + + status = centry->status; + + DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status %s\n", + domain->name, get_friendly_nt_error_msg(status) )); + + centry_free(centry); + return status; + +do_query: + ZERO_STRUCTP(lockout_policy); + + /* Return status value returned by seq number check */ + + if (!NT_STATUS_IS_OK(domain->last_status)) + return domain->last_status; + + DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n", + domain->name )); + + status = domain->backend->lockout_policy(domain, mem_ctx, lockout_policy); + + /* and save it */ + refresh_sequence_number(domain, False); + wcache_save_lockout_policy(domain, status, lockout_policy); + + return status; +} + +/* get password policy */ +static NTSTATUS password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_1 *password_policy) +{ + struct winbind_cache *cache = get_cache(domain); + struct cache_entry *centry = NULL; + NTSTATUS status; + + if (!cache->tdb) + goto do_query; + + centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name); + + if (!centry) + goto do_query; + + password_policy->min_length_password = centry_uint16(centry); + password_policy->password_history = centry_uint16(centry); + password_policy->password_properties = centry_uint32(centry); + password_policy->expire = centry_nttime(centry); + password_policy->min_passwordage = centry_nttime(centry); + + status = centry->status; + + DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status %s\n", + domain->name, get_friendly_nt_error_msg(status) )); + + centry_free(centry); + return status; + +do_query: + ZERO_STRUCTP(password_policy); + + /* Return status value returned by seq number check */ + + if (!NT_STATUS_IS_OK(domain->last_status)) + return domain->last_status; + + DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n", + domain->name )); + + status = domain->backend->password_policy(domain, mem_ctx, password_policy); + + /* and save it */ + refresh_sequence_number(domain, False); + wcache_save_password_policy(domain, status, password_policy); - /* we don't cache this call */ - return domain->backend->trusted_domains(domain, mem_ctx, num_domains, - names, alt_names, dom_sids); + return status; } + /* Invalidate cached user and group lists coherently */ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, @@ -1448,22 +1836,6 @@ void wcache_invalidate_cache(void) } } -/* the ADS backend methods are exposed via this structure */ -struct winbindd_methods cache_methods = { - True, - query_user_list, - enum_dom_groups, - enum_local_groups, - name_to_sid, - sid_to_name, - query_user, - lookup_usergroups, - lookup_useraliases, - lookup_groupmem, - sequence_number, - trusted_domains, -}; - static BOOL init_wcache(void) { if (wcache == NULL) { @@ -1474,8 +1846,10 @@ static BOOL init_wcache(void) if (wcache->tdb != NULL) return True; - wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000, - TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600); + /* when working offline we must not clear the cache on restart */ + wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), + WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, + TDB_DEFAULT /*TDB_CLEAR_IF_FIRST*/, O_RDWR|O_CREAT, 0600); if (wcache->tdb == NULL) { DEBUG(0,("Failed to open winbindd_cache.tdb!\n")); @@ -1577,6 +1951,25 @@ BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response) return True; } +void cache_cleanup_response(pid_t pid) +{ + fstring key_str; + + if (!init_wcache()) + return; + + DEBUG(10,("Cleaning up response for pid %d\n", pid)); + + fstr_sprintf(key_str, "DR/%d", pid); + tdb_delete(wcache->tdb, string_tdb_data(key_str)); + + fstr_sprintf(key_str, "DE/%d", pid); + tdb_delete(wcache->tdb, string_tdb_data(key_str)); + + return; +} + + BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, const char **domain_name, const char **name, enum SID_NAME_USE *type) @@ -1613,6 +2006,48 @@ BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, return NT_STATUS_IS_OK(status); } +BOOL lookup_cached_name(TALLOC_CTX *mem_ctx, + const char *domain_name, + const char *name, + DOM_SID *sid, + enum SID_NAME_USE *type) +{ + struct winbindd_domain *domain; + struct winbind_cache *cache; + struct cache_entry *centry = NULL; + NTSTATUS status; + fstring uname; + + domain = find_lookup_domain_from_name(domain_name); + if (domain == NULL) { + return False; + } + + cache = get_cache(domain); + + if (cache->tdb == NULL) { + return False; + } + + fstrcpy(uname, name); + strupper_m(uname); + + centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname); + if (centry == NULL) { + return False; + } + + if (NT_STATUS_IS_OK(centry->status)) { + *type = (enum SID_NAME_USE)centry_uint32(centry); + centry_sid(centry, sid); + } + + status = centry->status; + centry_free(centry); + + return NT_STATUS_IS_OK(status); +} + void cache_sid2name(struct winbindd_domain *domain, const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type) @@ -1620,3 +2055,282 @@ void cache_sid2name(struct winbindd_domain *domain, const DOM_SID *sid, wcache_save_sid_to_name(domain, NT_STATUS_OK, sid, domain_name, name, type); } + +/* delete all centries that don't have NT_STATUS_OK set */ +static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, + TDB_DATA dbuf, void *state) +{ + struct cache_entry *centry; + char buf[1024]; + + if (!snprintf(buf, kbuf.dsize + 1, "%s", kbuf.dptr)) { + return 1; + } + + centry = wcache_fetch_raw(buf); + if (!centry) { + return 0; + } + + if (!NT_STATUS_IS_OK(centry->status)) { + DEBUG(10,("deleting centry %s\n", buf)); + tdb_delete(the_tdb, kbuf); + } + + centry_free(centry); + return 0; +} + +/* flush the cache */ +void wcache_flush_cache(void) +{ + extern BOOL opt_nocache; + + if (!wcache) + return; + if (wcache->tdb) { + tdb_close(wcache->tdb); + wcache->tdb = NULL; + } + if (opt_nocache) + return; + + /* when working offline we must not clear the cache on restart */ + wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), + WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, + TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600); + + if (!wcache->tdb) { + DEBUG(0,("Failed to open winbindd_cache.tdb!\n")); + } + + tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL); + + DEBUG(10,("wcache_flush_cache success\n")); +} + +/* Count cached creds */ + +static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, + void *state) +{ + int *cred_count = (int*)state; + + if (strncmp(kbuf.dptr, "CRED/", 5) == 0) { + (*cred_count)++; + } + return 0; +} + +NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count) +{ + struct winbind_cache *cache = get_cache(domain); + + *count = 0; + + if (!cache->tdb) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count); + + return NT_STATUS_OK; +} + +struct cred_list { + struct cred_list *prev, *next; + TDB_DATA key; + fstring name; + time_t created; +}; +static struct cred_list *wcache_cred_list; + +static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, + void *state) +{ + struct cred_list *cred; + + if (strncmp(kbuf.dptr, "CRED/", 5) == 0) { + + cred = SMB_MALLOC_P(struct cred_list); + if (cred == NULL) { + DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n")); + return -1; + } + + ZERO_STRUCTP(cred); + + /* save a copy of the key */ + + fstrcpy(cred->name, kbuf.dptr); + DLIST_ADD(wcache_cred_list, cred); + } + + return 0; +} + +NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid) +{ + struct winbind_cache *cache = get_cache(domain); + NTSTATUS status; + int ret; + struct cred_list *cred, *oldest = NULL; + + if (!cache->tdb) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + /* we possibly already have an entry */ + if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) { + + fstring key_str; + + DEBUG(11,("we already have an entry, deleting that\n")); + + fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid)); + + tdb_delete(cache->tdb, string_tdb_data(key_str)); + + return NT_STATUS_OK; + } + + ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL); + if (ret == 0) { + return NT_STATUS_OK; + } else if (ret == -1) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + ZERO_STRUCTP(oldest); + + for (cred = wcache_cred_list; cred; cred = cred->next) { + + TDB_DATA data; + time_t t; + + data = tdb_fetch(cache->tdb, make_tdb_data(cred->name, strlen(cred->name))); + if (!data.dptr) { + DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n", + cred->name)); + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto done; + } + + t = IVAL(data.dptr, 0); + SAFE_FREE(data.dptr); + + if (!oldest) { + oldest = SMB_MALLOC_P(struct cred_list); + if (oldest == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + fstrcpy(oldest->name, cred->name); + oldest->created = t; + continue; + } + + if (t < oldest->created) { + fstrcpy(oldest->name, cred->name); + oldest->created = t; + } + } + + if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) { + status = NT_STATUS_OK; + } else { + status = NT_STATUS_UNSUCCESSFUL; + } +done: + SAFE_FREE(wcache_cred_list); + SAFE_FREE(oldest); + + return status; +} + +/* Change the global online/offline state. */ +BOOL set_global_winbindd_state_offline(void) +{ + TDB_DATA data; + int err; + + DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n")); + + /* Only go offline if someone has created + the key "WINBINDD_OFFLINE" in the cache tdb. */ + + if (wcache == NULL || wcache->tdb == NULL) { + DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n")); + return False; + } + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n")); + return False; + } + + if (global_winbindd_offline_state) { + /* Already offline. */ + return True; + } + + wcache->tdb->ecode = 0; + + data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" ); + + /* As this is a key with no data we don't need to free, we + check for existence by looking at tdb_err. */ + + err = tdb_error(wcache->tdb); + + if (err == TDB_ERR_NOEXIST) { + DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n")); + return False; + } else { + DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n")); + global_winbindd_offline_state = True; + return True; + } +} + +void set_global_winbindd_state_online(void) +{ + DEBUG(10,("set_global_winbindd_state_online: online requested.\n")); + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("set_global_winbindd_state_online: rejecting.\n")); + return; + } + + if (!global_winbindd_offline_state) { + /* Already online. */ + return; + } + global_winbindd_offline_state = False; + + if (!wcache->tdb) { + return; + } + + /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */ + tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE"); +} + +/* the cache backend methods are exposed via this structure */ +struct winbindd_methods cache_methods = { + True, + query_user_list, + enum_dom_groups, + enum_local_groups, + name_to_sid, + sid_to_name, + query_user, + lookup_usergroups, + lookup_useraliases, + lookup_groupmem, + sequence_number, + lockout_policy, + password_policy, + trusted_domains +}; diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index 177ac54d3ed..568078f86e5 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/nsswitch/winbindd_cm.c @@ -784,26 +784,32 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; - if ((strlen(domain->dcname) > 0) - && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname)) - && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20))) + if ((strlen(domain->dcname) > 0) + && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname)) + && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20))) { struct sockaddr_in *addrs = NULL; int num_addrs = 0; int dummy = 0; - add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs); add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs); if (!open_any_socket_out(addrs, num_addrs, 10000, &dummy, &fd)) { + domain->online = False; fd = -1; } } if ((fd == -1) - && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd)) + && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd)) { + /* This is the one place where we will + set the global winbindd offline state + to true, if a "WINBINDD_OFFLINE" entry + is found in the winbindd cache. */ + set_global_winbindd_state_offline(); + domain->online = False; break; } @@ -816,11 +822,19 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, break; } + if (NT_STATUS_IS_OK(result)) { + if (domain->online == False) { + /* We're changing state from offline to online. */ + set_global_winbindd_state_online(); + } + domain->online = True; + } + talloc_destroy(mem_ctx); return result; } -/* Return true if a connection is still alive */ +/* Close down all open pipes on a connection. */ void invalidate_cm_connection(struct winbindd_cm_conn *conn) { diff --git a/source/nsswitch/winbindd_cred_cache.c b/source/nsswitch/winbindd_cred_cache.c new file mode 100644 index 00000000000..a8aab04031a --- /dev/null +++ b/source/nsswitch/winbindd_cred_cache.c @@ -0,0 +1,270 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon - krb5 credential cache funcions + + Copyright (C) Guenther Deschner 2005 + + 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" +#include "winbindd.h" +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +#define MAX_CCACHES 100 + +static struct WINBINDD_CCACHE_ENTRY *ccache_list; + +static TALLOC_CTX *mem_ctx; + +const char *get_ccache_name_by_username(const char *username) +{ + struct WINBINDD_CCACHE_ENTRY *entry; + + for (entry = ccache_list; entry; entry = entry->next) { + if (strequal(entry->username, username)) { + return entry->ccname; + } + } + return NULL; +} + +struct WINBINDD_CCACHE_ENTRY *get_ccache_by_username(const char *username) +{ + struct WINBINDD_CCACHE_ENTRY *entry; + + for (entry = ccache_list; entry; entry = entry->next) { + if (strequal(entry->username, username)) { + return entry; + } + } + return NULL; +} + +static int ccache_entry_count(void) +{ + struct WINBINDD_CCACHE_ENTRY *entry; + int i = 0; + + for (entry = ccache_list; entry; entry = entry->next) { + i++; + } + return i; +} + +NTSTATUS remove_ccache_by_ccname(const char *ccname) +{ + struct WINBINDD_CCACHE_ENTRY *entry; + + for (entry = ccache_list; entry; entry = entry->next) { + if (strequal(entry->ccname, ccname)) { + DLIST_REMOVE(ccache_list, entry); + talloc_free(entry->event); /* unregisters events */ + return talloc_free(entry) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + } + } + return NT_STATUS_OBJECT_NAME_NOT_FOUND; +} + +static void krb5_ticket_refresh_handler(struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + struct WINBINDD_CCACHE_ENTRY *entry = + talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY); + int ret; + time_t new_start; + struct timeval t; + + + DEBUG(10,("krb5_ticket_refresh_handler called\n")); + DEBUGADD(10,("event called for: %s, %s\n", entry->ccname, entry->username)); + + talloc_free(entry->event); + +#ifdef HAVE_KRB5 + + /* Kinit again if we have the user password and we can't renew the old + * tgt anymore */ + + if ((entry->renew_until < time(NULL)) && (entry->pass != NULL)) { + + seteuid(entry->uid); + + ret = kerberos_kinit_password(entry->principal_name, + entry->pass, + 0, /* hm, can we do time correction here ? */ + &entry->refresh_time, + &entry->renew_until, + entry->ccname, + False, /* no PAC required anymore */ + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME); + seteuid(0); + + if (ret) { + DEBUG(3,("could not re-kinit: %s\n", error_message(ret))); + talloc_free(entry->event); + return; + } + + DEBUG(10,("successful re-kinit for: %s in ccache: %s\n", + entry->principal_name, entry->ccname)); + + new_start = entry->refresh_time; + + goto done; + } + + seteuid(entry->uid); + + ret = smb_krb5_renew_ticket(entry->ccname, + entry->principal_name, + entry->service, + &new_start); + seteuid(0); + + if (ret) { + DEBUG(3,("could not renew tickets: %s\n", error_message(ret))); + /* maybe we are beyond the renewing window */ + return; + } + +done: + + t = timeval_set(new_start, 0); + + entry->event = add_timed_event(mem_ctx, + t, + "krb5_ticket_refresh_handler", + krb5_ticket_refresh_handler, + entry); + +#endif +} + +NTSTATUS add_ccache_to_list(const char *princ_name, + const char *ccname, + const char *service, + const char *username, + const char *sid_string, + const char *pass, + uid_t uid, + time_t create_time, + time_t ticket_end, + time_t renew_until, + BOOL schedule_refresh_event) +{ + struct WINBINDD_CCACHE_ENTRY *new_entry = NULL; + NTSTATUS status; + + if ((username == NULL && sid_string == NULL && princ_name == NULL) || + ccname == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = init_ccache_list(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (ccache_entry_count() + 1 > MAX_CCACHES) { + DEBUG(10,("add_ccache_to_list: max number of ccaches reached\n")); + return NT_STATUS_NO_MORE_ENTRIES; + } + + new_entry = TALLOC_P(mem_ctx, struct WINBINDD_CCACHE_ENTRY); + if (new_entry == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(new_entry); + + if (username) { + new_entry->username = talloc_strdup(mem_ctx, username); + NT_STATUS_HAVE_NO_MEMORY(new_entry->username); + } + if (sid_string) { + new_entry->sid_string = talloc_strdup(mem_ctx, sid_string); + NT_STATUS_HAVE_NO_MEMORY(new_entry->sid_string); + } + if (princ_name) { + new_entry->principal_name = talloc_strdup(mem_ctx, princ_name); + NT_STATUS_HAVE_NO_MEMORY(new_entry->principal_name); + } + if (service) { + new_entry->service = talloc_strdup(mem_ctx, service); + NT_STATUS_HAVE_NO_MEMORY(new_entry->service); + } + if (pass) { + new_entry->pass = talloc_strdup(mem_ctx, pass); + NT_STATUS_HAVE_NO_MEMORY(new_entry->pass); + } + + new_entry->create_time = create_time; + new_entry->renew_until = renew_until; + new_entry->ccname = talloc_strdup(mem_ctx, ccname); + if (new_entry->ccname == NULL) { + return NT_STATUS_NO_MEMORY; + } + new_entry->uid = uid; + + +#ifndef WITH_KCM /* no point in doing the refresh in KCM and by ourself */ + + if (schedule_refresh_event && renew_until > 0) { + + struct timeval t = timeval_set((ticket_end -1 ), 0); + + new_entry->event = add_timed_event(mem_ctx, + t, + "krb5_ticket_refresh_handler", + krb5_ticket_refresh_handler, + new_entry); + } +#endif /* WITH_KCM */ + + DLIST_ADD(ccache_list, new_entry); + + DEBUG(10,("add_ccache_to_list: added ccache [%s] for user [%s] to the list\n", ccname, username)); + + return NT_STATUS_OK; +} + +NTSTATUS destroy_ccache_list(void) +{ + return talloc_destroy(mem_ctx) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; +} + +NTSTATUS init_ccache_list(void) +{ + if (ccache_list) { + return NT_STATUS_OK; + } + + mem_ctx = talloc_init("winbindd_ccache_krb5_handling"); + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(ccache_list); + + return NT_STATUS_OK; +} diff --git a/source/nsswitch/winbindd_creds.c b/source/nsswitch/winbindd_creds.c new file mode 100644 index 00000000000..d37e9019dbd --- /dev/null +++ b/source/nsswitch/winbindd_creds.c @@ -0,0 +1,162 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon - cached credentials funcions + + Copyright (C) Guenther Deschner 2005 + + 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" +#include "winbindd.h" +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +#define MAX_CACHED_LOGINS 10 + +NTSTATUS winbindd_get_creds(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + NET_USER_INFO_3 **info3, + const uint8 *cached_nt_pass[NT_HASH_LEN]) +{ + NET_USER_INFO_3 *info; + NTSTATUS status; + + status = wcache_get_creds(domain, mem_ctx, sid, cached_nt_pass); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + info = netsamlogon_cache_get(mem_ctx, sid); + if (info == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + *info3 = info; + + return NT_STATUS_OK; +} + + +NTSTATUS winbindd_store_creds(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user, + const char *pass, + NET_USER_INFO_3 *info3, + const DOM_SID *user_sid) +{ + NTSTATUS status; + uchar nt_pass[NT_HASH_LEN]; + DOM_SID cred_sid; + + if (info3 != NULL) { + + DOM_SID sid; + sid_copy(&sid, &(info3->dom_sid.sid)); + sid_append_rid(&sid, info3->user_rid); + sid_copy(&cred_sid, &sid); + info3->user_flgs |= LOGON_CACHED_ACCOUNT; + + } else if (user_sid != NULL) { + + sid_copy(&cred_sid, user_sid); + + } else if (user != NULL) { + + /* do lookup ourself */ + + enum SID_NAME_USE type; + + if (!lookup_cached_name(mem_ctx, + domain->name, + user, + &cred_sid, + &type)) { + return NT_STATUS_NO_SUCH_USER; + } + } else { + return NT_STATUS_INVALID_PARAMETER; + } + + if (pass) { + + int count = 0; + + status = wcache_count_cached_creds(domain, &count); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(11,("we have %d cached creds\n", count)); + + if (count + 1 > MAX_CACHED_LOGINS) { + + DEBUG(10,("need to delete the oldest cached login\n")); + + status = wcache_remove_oldest_cached_creds(domain, &cred_sid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("failed to remove oldest cached cred: %s\n", + nt_errstr(status))); + return status; + } + } + + E_md4hash(pass, nt_pass); + + dump_data(100, (const char *)nt_pass, NT_HASH_LEN); + + status = wcache_save_creds(domain, mem_ctx, &cred_sid, nt_pass); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + if (info3 != NULL && user != NULL) { + if (!netsamlogon_cache_store(user, info3)) { + return NT_STATUS_ACCESS_DENIED; + } + } + + return NT_STATUS_OK; +} + +NTSTATUS winbindd_update_creds_by_info3(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user, + const char *pass, + NET_USER_INFO_3 *info3) +{ + return winbindd_store_creds(domain, mem_ctx, user, pass, info3, NULL); +} + +NTSTATUS winbindd_update_creds_by_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + const char *pass) +{ + return winbindd_store_creds(domain, mem_ctx, NULL, pass, NULL, sid); +} + +NTSTATUS winbindd_update_creds_by_name(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user, + const char *pass) +{ + return winbindd_store_creds(domain, mem_ctx, user, pass, NULL, NULL); +} + + diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c index 38030ee9ac8..1988f36b51d 100644 --- a/source/nsswitch/winbindd_dual.c +++ b/source/nsswitch/winbindd_dual.c @@ -197,6 +197,8 @@ static void async_reply_recv(void *private_data, BOOL success) SMB_ASSERT(cache_retrieve_response(child->pid, state->response)); + cache_cleanup_response(child->pid); + DLIST_REMOVE(child->requests, state); schedule_async_request(child); @@ -233,6 +235,8 @@ static void schedule_async_request(struct winbindd_child *child) setup_async_write(&child->event, request->request, sizeof(*request->request), async_main_request_sent, request); + + talloc_destroy(child->mem_ctx); return; } @@ -347,6 +351,7 @@ static struct winbindd_child_dispatch_table child_dispatch_table[] = { { WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence, "SHOW_SEQUENCE" }, { WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" }, { WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" }, + { WINBINDD_PAM_LOGOFF, winbindd_dual_pam_logoff, "PAM_LOGOFF" }, { WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct, "CHECK_MACHACC" }, { WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" }, { WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" }, @@ -356,8 +361,8 @@ static struct winbindd_child_dispatch_table child_dispatch_table[] = { { WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" }, { WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" }, { WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" }, - { WINBINDD_ALLOCATE_RID, winbindd_dual_allocate_rid, "ALLOCATE_RID" }, - { WINBINDD_ALLOCATE_RID_AND_GID, winbindd_dual_allocate_rid_and_gid, "ALLOCATE_RID_AND_GID" }, + { WINBINDD_ALLOCATE_UID, winbindd_dual_allocate_uid, "ALLOCATE_UID" }, + { WINBINDD_ALLOCATE_GID, winbindd_dual_allocate_gid, "ALLOCATE_GID" }, { WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups, "GETUSERDOMGROUPS" }, { WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases, "GETSIDALIASES" }, /* End of list */ @@ -444,6 +449,137 @@ void winbind_child_died(pid_t pid) schedule_async_request(child); } +/* Forward the online/offline messages to our children. */ +void winbind_msg_offline(int msg_type, struct process_id src, void *buf, size_t len) +{ + struct winbindd_child *child; + + DEBUG(10,("winbind_msg_offline: got offline message.\n")); + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("winbind_msg_offline: rejecting offline message.\n")); + return; + } + + /* Set our global state as offline. */ + if (!set_global_winbindd_state_offline()) { + DEBUG(10,("winbind_msg_offline: offline request failed.\n")); + return; + } + + for (child = children; child != NULL; child = child->next) { + DEBUG(10,("winbind_msg_offline: sending message to pid %u.\n", + (unsigned int)child->pid )); + message_send_pid(pid_to_procid(child->pid), MSG_WINBIND_OFFLINE, NULL, 0, False); + } +} + +/* Forward the online/offline messages to our children. */ +void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t len) +{ + struct winbindd_child *child; + + DEBUG(10,("winbind_msg_online: got online message.\n")); + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("winbind_msg_online: rejecting online message.\n")); + return; + } + + /* Set our global state as online. */ + set_global_winbindd_state_online(); + + for (child = children; child != NULL; child = child->next) { + DEBUG(10,("winbind_msg_online: sending message to pid %u.\n", + (unsigned int)child->pid )); + message_send_pid(pid_to_procid(child->pid), MSG_WINBIND_ONLINE, NULL, 0, False); + } +} + +static void account_lockout_policy_handler(struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + struct winbindd_child *child = private_data; + + struct winbindd_methods *methods; + SAM_UNK_INFO_12 lockout_policy; + NTSTATUS result; + + DEBUG(10,("account_lockout_policy_handler called\n")); + + if (child->timed_event) { + talloc_free(child->timed_event); + } + + methods = child->domain->methods; + + result = methods->lockout_policy(child->domain, child->mem_ctx, &lockout_policy); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("account_lockout_policy_handler: failed to call lockout_policy\n")); + return; + } + + child->timed_event = add_timed_event(child->mem_ctx, + timeval_current_ofs(3600, 0), + "account_lockout_policy_handler", + account_lockout_policy_handler, + child); +} + +/* Deal with a request to go offline. */ + +static void child_msg_offline(int msg_type, struct process_id src, void *buf, size_t len) +{ + struct winbindd_domain *domain; + + DEBUG(5,("child_msg_offline received.\n")); + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("child_msg_offline: rejecting offline message.\n")); + return; + } + + /* Set our global state as offline. */ + if (!set_global_winbindd_state_offline()) { + DEBUG(10,("child_msg_offline: offline request failed.\n")); + return; + } + + /* Mark all our domains as offline. */ + + for (domain = domain_list(); domain; domain = domain->next) { + DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name)); + domain->online = False; + } +} + +/* Deal with a request to go online. */ + +static void child_msg_online(int msg_type, struct process_id src, void *buf, size_t len) +{ + struct winbindd_domain *domain; + + DEBUG(5,("child_msg_online received.\n")); + + if (!lp_winbind_offline_logon()) { + DEBUG(10,("child_msg_online: rejecting online message.\n")); + return; + } + + /* Set our global state as online. */ + set_global_winbindd_state_online(); + + /* Mark everything online - delete any negative cache entries + to force an immediate reconnect. */ + + for (domain = domain_list(); domain; domain = domain->next) { + DEBUG(5,("child_msg_online: marking %s online.\n", domain->name)); + domain->online = True; + check_negative_conn_cache_timeout(domain->name, domain->dcname, 0); + } +} + static BOOL fork_domain_child(struct winbindd_child *child) { int fdpair[2]; @@ -459,10 +595,15 @@ static BOOL fork_domain_child(struct winbindd_child *child) ZERO_STRUCT(state); state.pid = getpid(); + /* Ensure we don't process messages whilst we're + changing the disposition for the child. */ + message_block(); + child->pid = sys_fork(); if (child->pid == -1) { DEBUG(0, ("Could not fork: %s\n", strerror(errno))); + message_unblock(); return False; } @@ -475,6 +616,8 @@ static BOOL fork_domain_child(struct winbindd_child *child) child->event.flags = 0; child->requests = NULL; add_fd_event(&child->event); + /* We're ok with online/offline messages now. */ + message_unblock(); return True; } @@ -495,12 +638,80 @@ static BOOL fork_domain_child(struct winbindd_child *child) lp_set_logfile(child->logfilename); reopen_logs(); } - + + /* Don't handle the same messages as our parent. */ + message_deregister(MSG_SMB_CONF_UPDATED); + message_deregister(MSG_SHUTDOWN); + message_deregister(MSG_WINBIND_OFFLINE); + message_deregister(MSG_WINBIND_ONLINE); + + /* The child is ok with online/offline messages now. */ + message_unblock(); + + child->mem_ctx = talloc_init("child_mem_ctx"); + if (child->mem_ctx == NULL) { + return False; + } + + if (child->domain != NULL) { + /* We might be in the idmap child...*/ + child->timed_event = add_timed_event( + child->mem_ctx, timeval_zero(), + "account_lockout_policy_handler", + account_lockout_policy_handler, + child); + } + + /* Handle online/offline messages. */ + message_register(MSG_WINBIND_OFFLINE,child_msg_offline); + message_register(MSG_WINBIND_ONLINE,child_msg_online); + while (1) { + + int ret; + fd_set read_fds; + struct timeval t; + struct timeval *tp; + struct timeval now; + /* free up any talloc memory */ lp_talloc_free(); main_loop_talloc_free(); + run_events(); + + GetTimeOfDay(&now); + + tp = get_timed_events_timeout(&t, (time_t)-1); + if (tp) { + DEBUG(11,("select will use timeout of %d seconds\n", (int)tp->tv_sec)); + } + + /* Handle messages */ + + message_dispatch(); + + FD_ZERO(&read_fds); + FD_SET(state.sock, &read_fds); + + ret = sys_select(state.sock + 1, &read_fds, NULL, NULL, tp); + + if (ret == 0) { + DEBUG(10,("nothing is ready yet, continue\n")); + continue; + } + + if (ret == -1 && errno == EINTR) { + /* We got a signal - continue. */ + continue; + } + + if (ret == -1 && errno != EINTR) { + DEBUG(0,("select error occured\n")); + perror("select"); + return False; + } + /* fetch a request from the main daemon */ child_read_request(&state); diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index ff2d19f5fc8..a328cebac4f 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -140,7 +140,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, /* make sure to allow machine accounts */ if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) { - DEBUG(3, ("name %s isn't a domain user\n", the_name)); + DEBUG(3, ("name %s isn't a domain user (%s)\n", the_name, sid_type_lookup(name_types[i]))); continue; } @@ -208,6 +208,8 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) char *tmp, *gr_mem; size_t gr_mem_len; gid_t gid; + union unid_t id; + NTSTATUS status; /* Ensure null termination */ state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0'; @@ -241,8 +243,8 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) /* should we deal with users for our domain? */ if ( lp_winbind_trusted_domains_only() && domain->primary) { - DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", - name_domain, name_group)); + DEBUG(7,("winbindd_getgrnam: My domain -- rejecting " + "getgrnam() for %s\\%s.\n", name_domain, name_group)); request_error(state); return; } @@ -262,18 +264,35 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) ((name_type==SID_NAME_ALIAS) && domain->internal) || ((name_type==SID_NAME_WKN_GRP) && domain->internal)) ) { - DEBUG(1, ("name '%s' is not a local, domain or builtin group: %d\n", - name_group, name_type)); + DEBUG(1, ("name '%s' is not a local, domain or builtin " + "group: %d\n", name_group, name_type)); request_error(state); return; } - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) { - DEBUG(1, ("error converting unix gid to sid\n")); - request_error(state); - return; + /* Try to get the GID */ + + status = idmap_sid_to_gid(&group_sid, &gid, 0); + + if (NT_STATUS_IS_OK(status)) { + goto got_gid; + } + + /* Maybe it's one of our aliases in passdb */ + + if (pdb_sid_to_id(&group_sid, &id, &name_type) && + ((name_type == SID_NAME_ALIAS) || + (name_type == SID_NAME_WKN_GRP))) { + gid = id.gid; + goto got_gid; } + DEBUG(1, ("error converting unix gid to sid\n")); + request_error(state); + return; + + got_gid: + if (!fill_grent(&state->response.data.gr, name_domain, name_group, gid) || !fill_grent_mem(domain, &group_sid, name_type, @@ -303,6 +322,7 @@ void winbindd_getgrgid(struct winbindd_cli_state *state) fstring group_name; size_t gr_mem_len; char *gr_mem; + NTSTATUS status; DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid, (unsigned long)state->request.data.gid)); @@ -315,14 +335,29 @@ void winbindd_getgrgid(struct winbindd_cli_state *state) return; } - /* Get rid from gid */ - if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) { - DEBUG(1, ("could not convert gid %lu to rid\n", - (unsigned long)state->request.data.gid)); - request_error(state); - return; + /* Get sid from gid */ + + status = idmap_gid_to_sid(&group_sid, state->request.data.gid, 0); + if (NT_STATUS_IS_OK(status)) { + /* This is a remote one */ + goto got_sid; } + /* Ok, this might be "ours", i.e. an alias */ + + if (pdb_gid_to_sid(state->request.data.gid, &group_sid) && + lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) && + (name_type == SID_NAME_ALIAS)) { + /* Hey, got an alias */ + goto got_sid; + } + + DEBUG(1, ("could not convert gid %lu to sid\n", + (unsigned long)state->request.data.gid)); + request_error(state); + return; + + got_sid: /* Get name from sid */ if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name, @@ -665,13 +700,32 @@ void winbindd_getgrent(struct winbindd_cli_state *state) sid_copy(&group_sid, &domain->sid); sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid); - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) { - - DEBUG(1, ("could not look up gid for group %s\n", - name_list[ent->sam_entry_index].acct_name)); - - ent->sam_entry_index++; - goto tryagain; + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, + &group_gid, 0))) { + union unid_t id; + enum SID_NAME_USE type; + + DEBUG(10, ("SID %s not in idmap\n", + sid_string_static(&group_sid))); + + if (!pdb_sid_to_id(&group_sid, &id, &type)) { + DEBUG(1, ("could not look up gid for group " + "%s\n", + name_list[ent->sam_entry_index].acct_name)); + ent->sam_entry_index++; + goto tryagain; + } + + if ((type != SID_NAME_DOM_GRP) && + (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + DEBUG(1, ("Group %s is a %s, not a group\n", + sid_type_lookup(type), + name_list[ent->sam_entry_index].acct_name)); + ent->sam_entry_index++; + goto tryagain; + } + group_gid = id.gid; } DEBUG(10, ("got gid %lu for group %lu\n", (unsigned long)group_gid, @@ -1187,4 +1241,3 @@ enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *doma return WINBINDD_OK; } - diff --git a/source/nsswitch/winbindd_misc.c b/source/nsswitch/winbindd_misc.c index 1fbf4b33df2..b6aecae3930 100644 --- a/source/nsswitch/winbindd_misc.c +++ b/source/nsswitch/winbindd_misc.c @@ -115,6 +115,7 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain * int extra_data_len = 0; char *extra_data; NTSTATUS result; + BOOL have_own_domain = False; DEBUG(3, ("[%5lu]: list trusted domains\n", (unsigned long)state->pid)); @@ -137,6 +138,22 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain * names[i], alt_names[i] ? alt_names[i] : names[i], sid_string_static(&sids[i])); + /* add our primary domain */ + + for (i=0; iname)) { + have_own_domain = True; + break; + } + } + + if (state->request.data.list_all_domains && !have_own_domain) { + extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s", + extra_data, + domain->name, + domain->alt_name ? domain->alt_name : domain->name, + sid_string_static(&domain->sid)); + } /* This is a bit excessive, but the extra data sooner or later will be talloc'ed */ diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h index eda68ae5c71..033e51d7943 100644 --- a/source/nsswitch/winbindd_nss.h +++ b/source/nsswitch/winbindd_nss.h @@ -34,7 +34,7 @@ /* Update this when you change the interface. */ -#define WINBIND_INTERFACE_VERSION 11 +#define WINBIND_INTERFACE_VERSION 14 /* Socket commands */ @@ -64,6 +64,7 @@ enum winbindd_cmd { WINBINDD_PAM_AUTH, WINBINDD_PAM_AUTH_CRAP, WINBINDD_PAM_CHAUTHTOK, + WINBINDD_PAM_LOGOFF, /* List various things */ @@ -82,8 +83,9 @@ enum winbindd_cmd { WINBINDD_SID_TO_GID, WINBINDD_UID_TO_SID, WINBINDD_GID_TO_SID, - WINBINDD_ALLOCATE_RID, - WINBINDD_ALLOCATE_RID_AND_GID, + + WINBINDD_ALLOCATE_UID, + WINBINDD_ALLOCATE_GID, /* Miscellaneous other stuff */ @@ -114,7 +116,7 @@ enum winbindd_cmd { /* return a list of group sids for a user sid */ WINBINDD_GETUSERSIDS, - /* Return the domain groups a user is in */ + /* Various group queries */ WINBINDD_GETUSERDOMGROUPS, /* Initialize connection in a child */ @@ -165,7 +167,6 @@ typedef struct winbindd_gr { #define WBFLAG_PAM_LMKEY 0x0008 #define WBFLAG_PAM_CONTACT_TRUSTDOM 0x0010 #define WBFLAG_QUERY_ONLY 0x0020 -#define WBFLAG_ALLOCATE_RID 0x0040 #define WBFLAG_PAM_UNIX_NAME 0x0080 #define WBFLAG_PAM_AFS_TOKEN 0x0100 #define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200 @@ -175,6 +176,10 @@ typedef struct winbindd_gr { /* Flag to say this is a winbindd internal send - don't recurse. */ #define WBFLAG_RECURSE 0x0800 +#define WBFLAG_PAM_KRB5 0x1000 +#define WBFLAG_PAM_FALLBACK_AFTER_KRB5 0x2000 +#define WBFLAG_PAM_CACHED_LOGIN 0x4000 + #define WINBINDD_MAX_EXTRA_DATA (128*1024) /* Winbind request structure */ @@ -199,6 +204,8 @@ struct winbindd_request { fstring user; fstring pass; fstring require_membership_of_sid; + fstring krb5_cc_type; + uid_t uid; } auth; /* pam_winbind auth module */ struct { unsigned char chal[8]; @@ -217,6 +224,11 @@ struct winbindd_request { fstring oldpass; fstring newpass; } chauthtok; /* pam_winbind passwd module */ + struct { + fstring user; + fstring krb5ccname; + uid_t uid; + } logoff; /* pam_winbind session module */ fstring sid; /* lookupsid, sid_to_[ug]id */ struct { fstring dom_name; /* lookupname */ @@ -242,6 +254,7 @@ struct winbindd_request { gid_t gid; fstring sid; } dual_idmapset; + BOOL list_all_domains; } data; char *extra_data; size_t extra_len; @@ -307,12 +320,41 @@ struct winbindd_response { int pam_error; char user_session_key[16]; char first_8_lm_hash[8]; + fstring krb5ccname; + struct policy_settings { + uint16 min_length_password; + uint16 password_history; + uint32 password_properties; + time_t expire; + time_t min_passwordage; + } policy; + uint32 reject_reason; + struct info3_text { + time_t logon_time; + time_t logoff_time; + time_t kickoff_time; + time_t pass_last_set_time; + time_t pass_can_change_time; + time_t pass_must_change_time; + uint16 logon_count; + uint16 bad_pw_count; + fstring user_sid; + fstring group_sid; + fstring dom_sid; + uint32 num_groups; + uint32 user_flgs; + uint32 acct_flags; + uint32 num_other_sids; + fstring user_name; + fstring full_name; + fstring logon_script; + fstring profile_path; + fstring home_dir; + fstring dir_drive; + fstring logon_srv; + fstring logon_dom; + } info3; } auth; - uint32 rid; /* create user or group or allocate rid */ - struct { - uint32 rid; - gid_t gid; - } rid_and_gid; struct { fstring name; fstring alt_name; @@ -336,4 +378,20 @@ struct winbindd_response { void *extra_data; /* getgrnam, getgrgid, getgrent */ }; +struct WINBINDD_CCACHE_ENTRY { + const char *principal_name; + const char *ccname; + const char *service; + const char *username; + const char *sid_string; + const char *pass; + uid_t uid; + time_t create_time; + time_t renew_until; + BOOL refresh_tgt; + time_t refresh_time; + struct timed_event *event; + struct WINBINDD_CCACHE_ENTRY *next, *prev; +}; + #endif diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c index 890007ae389..ab20102f79f 100644 --- a/source/nsswitch/winbindd_pam.c +++ b/source/nsswitch/winbindd_pam.c @@ -6,6 +6,7 @@ Copyright (C) Andrew Tridgell 2000 Copyright (C) Tim Potter 2001 Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Guenther Deschner 2005 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 @@ -27,6 +28,70 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx, + struct winbindd_cli_state *state, + NET_USER_INFO_3 *info3) +{ + DOM_SID user_sid, group_sid; + fstring str_sid; + + state->response.data.auth.info3.logon_time = + nt_time_to_unix(&(info3->logon_time)); + state->response.data.auth.info3.logoff_time = + nt_time_to_unix(&(info3->logoff_time)); + state->response.data.auth.info3.kickoff_time = + nt_time_to_unix(&(info3->kickoff_time)); + state->response.data.auth.info3.pass_last_set_time = + nt_time_to_unix(&(info3->pass_last_set_time)); + state->response.data.auth.info3.pass_can_change_time = + nt_time_to_unix(&(info3->pass_can_change_time)); + state->response.data.auth.info3.pass_must_change_time = + nt_time_to_unix(&(info3->pass_must_change_time)); + + state->response.data.auth.info3.logon_count = info3->logon_count; + state->response.data.auth.info3.bad_pw_count = info3->bad_pw_count; + + sid_copy(&user_sid, &(info3->dom_sid.sid)); + sid_append_rid(&user_sid, info3->user_rid); + + sid_to_string(str_sid, &user_sid); + fstrcpy(state->response.data.auth.info3.user_sid, str_sid); + + sid_copy(&group_sid, &(info3->dom_sid.sid)); + sid_append_rid(&group_sid, info3->group_rid); + + sid_to_string(str_sid, &group_sid); + fstrcpy(state->response.data.auth.info3.group_sid, str_sid); + + sid_to_string(str_sid, &(info3->dom_sid.sid)); + fstrcpy(state->response.data.auth.info3.dom_sid, str_sid); + + state->response.data.auth.info3.num_groups = info3->num_groups; + state->response.data.auth.info3.user_flgs = info3->user_flgs; + + state->response.data.auth.info3.acct_flags = info3->acct_flags; + state->response.data.auth.info3.num_other_sids = info3->num_other_sids; + + unistr2_to_ascii(state->response.data.auth.info3.user_name, + &info3->uni_user_name, -1); + unistr2_to_ascii(state->response.data.auth.info3.full_name, + &info3->uni_full_name, -1); + unistr2_to_ascii(state->response.data.auth.info3.logon_script, + &info3->uni_logon_script, -1); + unistr2_to_ascii(state->response.data.auth.info3.profile_path, + &info3->uni_profile_path, -1); + unistr2_to_ascii(state->response.data.auth.info3.home_dir, + &info3->uni_home_dir, -1); + unistr2_to_ascii(state->response.data.auth.info3.dir_drive, + &info3->uni_dir_drive, -1); + + unistr2_to_ascii(state->response.data.auth.info3.logon_srv, + &info3->uni_logon_srv, -1); + unistr2_to_ascii(state->response.data.auth.info3.logon_dom, + &info3->uni_logon_dom, -1); + + return NT_STATUS_OK; +} static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx, struct winbindd_cli_state *state, @@ -145,14 +210,15 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx, return NT_STATUS_LOGON_FAILURE; } -static struct winbindd_domain *find_auth_domain(const char *domain_name) +static struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state, + const char *domain_name) { struct winbindd_domain *domain; if (IS_DC) { domain = find_domain_from_name_noinit(domain_name); if (domain == NULL) { - DEBUG(3, ("Authentication for domain [%s] " + DEBUG(3, ("Authentication for domain [%s] refused" "as it is not a trusted domain\n", domain_name)); } @@ -166,6 +232,18 @@ static struct winbindd_domain *find_auth_domain(const char *domain_name) return NULL; } + /* we can auth against trusted domains */ + if (state->request.flags & WBFLAG_PAM_CONTACT_TRUSTDOM) { + domain = find_domain_from_name_noinit(domain_name); + if (domain == NULL) { + DEBUG(3, ("Authentication for domain [%s] skipped " + "as it is not a trusted domain\n", + domain_name)); + } else { + return domain; + } + } + return find_our_domain(); } @@ -181,9 +259,372 @@ static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result) resp->data.auth.pam_error = nt_status_to_pam(result); } +static NTSTATUS fillup_password_policy(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + struct winbindd_methods *methods; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + SAM_UNK_INFO_1 password_policy; + + methods = domain->methods; + + status = methods->password_policy(domain, state->mem_ctx, &password_policy); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + state->response.data.auth.policy.min_length_password = + password_policy.min_length_password; + state->response.data.auth.policy.password_history = + password_policy.password_history; + state->response.data.auth.policy.password_properties = + password_policy.password_properties; + state->response.data.auth.policy.expire = + nt_time_to_unix_abs(&(password_policy.expire)); + state->response.data.auth.policy.min_passwordage = + nt_time_to_unix_abs(&(password_policy.min_passwordage)); + + return NT_STATUS_OK; +} + +static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint16 *max_allowed_bad_attempts) +{ + struct winbindd_methods *methods; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + SAM_UNK_INFO_12 lockout_policy; + + *max_allowed_bad_attempts = 0; + + methods = domain->methods; + + status = methods->lockout_policy(domain, mem_ctx, &lockout_policy); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + *max_allowed_bad_attempts = lockout_policy.bad_attempt_lockout; + + return NT_STATUS_OK; +} + + +static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx, + const char *type, + uid_t uid, + BOOL *internal_ccache) +{ + /* accept KCM, FILE and WRFILE as krb5_cc_type from the client and then + * build the full ccname string based on the user's uid here - + * Guenther*/ + + const char *gen_cc = NULL; + + *internal_ccache = True; + + if (uid == -1) { + goto memory_ccache; + } + + if (!type || type[0] == '\0') { + goto memory_ccache; + } + + if (strequal(type, "FILE")) { + gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid); + } else if (strequal(type, "WRFILE")) { + gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid); +#ifdef WITH_KCM + } else if (strequal(type, "KCM")) { + gen_cc = talloc_asprintf(mem_ctx, "KCM:%d", uid); +#endif + } else { + DEBUG(10,("we don't allow to set a %s type ccache\n", type)); + goto memory_ccache; + } + + *internal_ccache = False; + goto done; + + memory_ccache: + gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbind_cache"); + + done: + if (gen_cc == NULL) { + DEBUG(0,("out of memory\n")); + return NULL; + } + + DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":"")); + + return gen_cc; +} + +static uid_t get_uid_from_state(struct winbindd_cli_state *state) +{ + uid_t uid = -1; + + uid = state->request.data.auth.uid; + + if (uid < 0) { + DEBUG(1,("invalid uid: '%d'\n", uid)); + return -1; + } + return uid; +} + +static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc) +{ + const char *type = state->request.data.auth.krb5_cc_type; + + state->response.data.auth.krb5ccname[0] = '\0'; + + if (type[0] == '\0') { + return; + } + + if (!strequal(type, "FILE") && +#ifdef WITH_KCM + !strequal(type, "KCM") && +#endif + !strequal(type, "WRFILE")) { + DEBUG(10,("won't return krbccname for a %s type ccache\n", + type)); + return; + } + + fstrcpy(state->response.data.auth.krb5ccname, cc); +} + /********************************************************************** - Authenticate a user with a clear text password -**********************************************************************/ + Authenticate a user with a clear text password using Kerberos and fill up + ccache if required + **********************************************************************/ +static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain, + struct winbindd_cli_state *state, + NET_USER_INFO_3 **info3) +{ +#ifdef HAVE_KRB5 + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + krb5_error_code krb5_ret; + DATA_BLOB tkt, session_key_krb5; + DATA_BLOB ap_rep, session_key; + PAC_DATA *pac_data = NULL; + PAC_LOGON_INFO *logon_info = NULL; + char *client_princ = NULL; + char *client_princ_out = NULL; + char *local_service = NULL; + const char *cc = NULL; + const char *principal_s = NULL; + const char *service = NULL; + char *realm = NULL; + fstring name_domain, name_user; + time_t ticket_lifetime = 0; + time_t renewal_until = 0; + uid_t uid = -1; + ADS_STRUCT *ads; + time_t time_offset = 0; + BOOL internal_ccache = True; + + ZERO_STRUCT(session_key); + ZERO_STRUCT(session_key_krb5); + ZERO_STRUCT(tkt); + ZERO_STRUCT(ap_rep); + + ZERO_STRUCTP(info3); + + *info3 = NULL; + + /* 1st step: + * prepare a krb5_cc_cache string for the user */ + + uid = get_uid_from_state(state); + if (uid == -1) { + DEBUG(0,("no valid uid\n")); + } + + cc = generate_krb5_ccache(state->mem_ctx, + state->request.data.auth.krb5_cc_type, + state->request.data.auth.uid, + &internal_ccache); + if (cc == NULL) { + return NT_STATUS_NO_MEMORY; + } + + + /* 2nd step: + * get kerberos properties */ + + if (domain->private_data) { + ads = (ADS_STRUCT *)domain->private_data; + time_offset = ads->auth.time_offset; + } + + + /* 3rd step: + * do kerberos auth and setup ccache as the user */ + + parse_domain_user(state->request.data.auth.user, name_domain, name_user); + + realm = domain->alt_name; + strupper_m(realm); + + principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm); + if (principal_s == NULL) { + return NT_STATUS_NO_MEMORY; + } + + service = talloc_asprintf(state->mem_ctx, "krbtgt/%s@%s", realm, realm); + if (service == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* if this is a user ccache, we need to act as the user to let the krb5 + * library handle the chown, etc. */ + + /************************ NON-ROOT **********************/ + + if (!internal_ccache) { + + seteuid(uid); + DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid)); + } + + krb5_ret = kerberos_kinit_password(principal_s, + state->request.data.auth.pass, + time_offset, + &ticket_lifetime, + &renewal_until, + cc, + True, + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME); + + if (krb5_ret) { + DEBUG(1,("winbindd_raw_kerberos_login: kinit failed for '%s' with: %s (%d)\n", + principal_s, error_message(krb5_ret), krb5_ret)); + result = krb5_to_nt_status(krb5_ret); + goto done; + } + + /* does http_timestring use heimdals libroken strftime?? - Guenther */ + DEBUG(10,("got TGT for %s in %s (valid until: %s (%d), renewable till: %s (%d))\n", + principal_s, cc, + http_timestring(ticket_lifetime), (int)ticket_lifetime, + http_timestring(renewal_until), (int)renewal_until)); + + client_princ = talloc_strdup(state->mem_ctx, global_myname()); + if (client_princ == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + strlower_m(client_princ); + + local_service = talloc_asprintf(state->mem_ctx, "HOST/%s@%s", client_princ, lp_realm()); + if (local_service == NULL) { + DEBUG(0,("winbindd_raw_kerberos_login: out of memory\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + krb5_ret = cli_krb5_get_ticket(local_service, + time_offset, + &tkt, + &session_key_krb5, + 0, + cc); + if (krb5_ret) { + DEBUG(1,("winbindd_raw_kerberos_login: failed to get ticket for: %s\n", + local_service)); + result = krb5_to_nt_status(krb5_ret); + goto done; + } + + if (!internal_ccache) { + seteuid(0); + } + + /************************ NON-ROOT **********************/ + + result = ads_verify_ticket(state->mem_ctx, + lp_realm(), + &tkt, + &client_princ_out, + &pac_data, + &ap_rep, + &session_key); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0,("winbindd_raw_kerberos_login: ads_verify_ticket failed: %s\n", + nt_errstr(result))); + goto done; + } + + DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n", + client_princ)); + + if (!pac_data) { + DEBUG(3,("winbindd_raw_kerberos_login: no pac data\n")); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + logon_info = get_logon_info_from_pac(pac_data); + if (logon_info == NULL) { + DEBUG(1,("winbindd_raw_kerberos_login: no logon info\n")); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + + /* last step: + * put results together */ + + *info3 = &logon_info->info3; + + /* if we had a user's ccache then return that string for the pam + * environment */ + + if (!internal_ccache) { + + setup_return_cc_name(state, cc); + + result = add_ccache_to_list(principal_s, + cc, + service, + state->request.data.auth.user, + NULL, + state->request.data.auth.pass, + uid, + time(NULL), + ticket_lifetime, + renewal_until, + lp_winbind_refresh_tickets()); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", + nt_errstr(result))); + } + } + + result = NT_STATUS_OK; + +done: + data_blob_free(&session_key); + data_blob_free(&session_key_krb5); + data_blob_free(&ap_rep); + data_blob_free(&tkt); + + SAFE_FREE(client_princ_out); + + if (!internal_ccache) { + seteuid(0); + } + + return result; +#else + return NT_STATUS_NOT_SUPPORTED; +#endif /* HAVE_KRB5 */ +} void winbindd_pam_auth(struct winbindd_cli_state *state) { @@ -206,7 +647,7 @@ void winbindd_pam_auth(struct winbindd_cli_state *state) parse_domain_user(state->request.data.auth.user, name_domain, name_user); - domain = find_auth_domain(name_domain); + domain = find_auth_domain(state, name_domain); if (domain == NULL) { set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER); @@ -222,12 +663,221 @@ void winbindd_pam_auth(struct winbindd_cli_state *state) sendto_domain(state, domain); } -enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, - struct winbindd_cli_state *state) +NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, + struct winbindd_cli_state *state, + NET_USER_INFO_3 **info3) { - NTSTATUS result; + NTSTATUS result = NT_STATUS_LOGON_FAILURE; + uint16 max_allowed_bad_attempts; fstring name_domain, name_user; - NET_USER_INFO_3 info3; + DOM_SID sid; + enum SID_NAME_USE type; + uchar new_nt_pass[NT_HASH_LEN]; + const uint8 *cached_nt_pass; + NET_USER_INFO_3 *my_info3; + time_t kickoff_time, must_change_time; + + *info3 = NULL; + + ZERO_STRUCTP(info3); + + DEBUG(10,("winbindd_dual_pam_auth_cached\n")); + + /* Parse domain and username */ + + parse_domain_user(state->request.data.auth.user, name_domain, name_user); + + + if (!lookup_cached_name(state->mem_ctx, + name_domain, + name_user, + &sid, + &type)) { + DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n")); + return NT_STATUS_NO_SUCH_USER; + } + + if (type != SID_NAME_USER) { + DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type))); + return NT_STATUS_LOGON_FAILURE; + } + + result = winbindd_get_creds(domain, + state->mem_ctx, + &sid, + &my_info3, + &cached_nt_pass); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result))); + return result; + } + + *info3 = my_info3; + + E_md4hash(state->request.data.auth.pass, new_nt_pass); + + dump_data(100, (const char *)new_nt_pass, NT_HASH_LEN); + dump_data(100, (const char *)cached_nt_pass, NT_HASH_LEN); + + if (!memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN)) { + + /* User *DOES* know the password, update logon_time and reset + * bad_pw_count */ + + my_info3->user_flgs |= LOGON_CACHED_ACCOUNT; + + if (my_info3->acct_flags & ACB_AUTOLOCK) { + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + + if (my_info3->acct_flags & ACB_DISABLED) { + return NT_STATUS_ACCOUNT_DISABLED; + } + + if (my_info3->acct_flags & ACB_WSTRUST) { + return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT; + } + + if (my_info3->acct_flags & ACB_SVRTRUST) { + return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT; + } + + if (my_info3->acct_flags & ACB_DOMTRUST) { + return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT; + } + + if (!(my_info3->acct_flags & ACB_NORMAL)) { + DEBUG(10,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n", + my_info3->acct_flags)); + return NT_STATUS_LOGON_FAILURE; + } + + kickoff_time = nt_time_to_unix(&my_info3->kickoff_time); + if (kickoff_time != 0 && time(NULL) > kickoff_time) { + return NT_STATUS_ACCOUNT_EXPIRED; + } + + must_change_time = nt_time_to_unix(&my_info3->pass_must_change_time); + if (must_change_time != 0 && must_change_time < time(NULL)) { + return NT_STATUS_PASSWORD_EXPIRED; + } + + /* FIXME: we possibly should handle logon hours as well (does xp when + * offline?) see auth/auth_sam.c:sam_account_ok for details */ + + unix_to_nt_time(&my_info3->logon_time, time(NULL)); + my_info3->bad_pw_count = 0; + + result = winbindd_update_creds_by_info3(domain, + state->mem_ctx, + state->request.data.auth.user, + state->request.data.auth.pass, + my_info3); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(1,("failed to update creds: %s\n", nt_errstr(result))); + return result; + } + + return NT_STATUS_OK; + + } + + /* User does *NOT* know the correct password, modify info3 accordingly */ + + /* failure of this is not critical */ + result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. " + "Won't be able to honour account lockout policies\n")); + } + + if (max_allowed_bad_attempts == 0) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* increase counter */ + if (my_info3->bad_pw_count < max_allowed_bad_attempts) { + + my_info3->bad_pw_count++; + } + + /* lockout user */ + if (my_info3->bad_pw_count >= max_allowed_bad_attempts) { + + my_info3->acct_flags |= ACB_AUTOLOCK; + } + + result = winbindd_update_creds_by_info3(domain, + state->mem_ctx, + state->request.data.auth.user, + NULL, + my_info3); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n", + nt_errstr(result))); + } + + return NT_STATUS_LOGON_FAILURE; +} + +NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain, + struct winbindd_cli_state *state, + NET_USER_INFO_3 **info3) +{ + struct winbindd_domain *contact_domain; + fstring name_domain, name_user; + NTSTATUS result; + + DEBUG(10,("winbindd_dual_pam_auth_kerberos\n")); + + /* Parse domain and username */ + + parse_domain_user(state->request.data.auth.user, name_domain, name_user); + + /* what domain should we contact? */ + + if ( IS_DC ) { + if (!(contact_domain = find_domain_from_name(name_domain))) { + DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", + state->request.data.auth.user, name_domain, name_user, name_domain)); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + } else { + if (is_myname(name_domain)) { + DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain)); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + contact_domain = find_domain_from_name(name_domain); + if (contact_domain == NULL) { + DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", + state->request.data.auth.user, name_domain, name_user, name_domain)); + + contact_domain = find_our_domain(); + } + } + + set_dc_type_and_flags(contact_domain); + + if (!contact_domain->active_directory) { + DEBUG(3,("krb5 auth requested but domain is not Active Directory\n")); + return NT_STATUS_INVALID_LOGON_TYPE; + } + + result = winbindd_raw_kerberos_login(contact_domain, state, info3); +done: + return result; +} + +NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain, + struct winbindd_cli_state *state, + NET_USER_INFO_3 **info3) +{ + struct rpc_pipe_client *netlogon_pipe; uchar chal[8]; DATA_BLOB lm_resp; @@ -236,17 +886,23 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; struct winbindd_domain *contact_domain; + fstring name_domain, name_user; BOOL retry; + NTSTATUS result; + NET_USER_INFO_3 *my_info3; - /* Ensure null termination */ - state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; + ZERO_STRUCTP(info3); - /* Ensure null termination */ - state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0'; + *info3 = NULL; - DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid, - state->request.data.auth.user)); + my_info3 = TALLOC_ZERO_P(state->mem_ctx, NET_USER_INFO_3); + if (my_info3 == NULL) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("winbindd_dual_pam_auth_samlogon\n")); + /* Parse domain and username */ parse_domain_user(state->request.data.auth.user, name_domain, name_user); @@ -332,7 +988,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, do { - ZERO_STRUCT(info3); + ZERO_STRUCTP(my_info3); retry = False; result = cm_connect_netlogon(contact_domain, &netlogon_pipe); @@ -352,7 +1008,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, chal, lm_resp, nt_resp, - &info3); + my_info3); attempts += 1; /* We have to try a second time as cm_connect_netlogon @@ -381,25 +1037,154 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, } while ( (attempts < 2) && retry ); + *info3 = my_info3; +done: + return result; +} + +enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + NTSTATUS result = NT_STATUS_LOGON_FAILURE; + fstring name_domain, name_user; + NET_USER_INFO_3 *info3; + + /* Ensure null termination */ + state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; + + /* Ensure null termination */ + state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0'; + + DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid, + state->request.data.auth.user)); + + /* Parse domain and username */ + + parse_domain_user(state->request.data.auth.user, name_domain, name_user); + + DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline")); + + /* Check for Kerberos authentication */ + if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) { + + result = winbindd_dual_pam_auth_kerberos(domain, state, &info3); + + if (NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n")); + goto process_result; + } else { + DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result))); + } + + if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)) { + DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n")); + domain->online = False; + } + + if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) { + DEBUG(3,("falling back to samlogon\n")); + goto sam_logon; + } else { + goto cached_logon; + } + } + +sam_logon: + /* Check for Samlogon authentication */ + if (domain->online) { + result = winbindd_dual_pam_auth_samlogon(domain, state, &info3); + + if (NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n")); + goto process_result; + } else { + DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n", nt_errstr(result))); + if (domain->online) { + /* We're still online - fail. */ + goto done; + } + /* Else drop through and see if we can check offline.... */ + } + } + +cached_logon: + /* Check for Cached logons */ + if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) && + lp_winbind_offline_logon()) { + + result = winbindd_dual_pam_auth_cached(domain, state, &info3); + + if (NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n")); + goto process_result; + } else { + DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result))); + goto done; + } + } + +process_result: + if (NT_STATUS_IS_OK(result)) { - netsamlogon_cache_store(name_user, &info3); - wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3); + + netsamlogon_cache_store(name_user, info3); + wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3); /* Check if the user is in the right group */ - if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3, + if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3, state->request.data.auth.require_membership_of_sid))) { DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n", state->request.data.auth.user, state->request.data.auth.require_membership_of_sid)); + goto done; } - } -done: + if (state->request.flags & WBFLAG_PAM_INFO3_NDR) { + result = append_info3_as_ndr(state->mem_ctx, state, info3); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("Failed to append INFO3 (NDR): %s\n", nt_errstr(result))); + goto done; + } + } + + if (state->request.flags & WBFLAG_PAM_INFO3_TEXT) { + result = append_info3_as_txt(state->mem_ctx, state, info3); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("Failed to append INFO3 (TXT): %s\n", nt_errstr(result))); + goto done; + } + + } + if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN) && + lp_winbind_offline_logon()) { + + result = winbindd_store_creds(domain, + state->mem_ctx, + state->request.data.auth.user, + state->request.data.auth.pass, + info3, NULL); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result))); + goto done; + } + + } + + result = fillup_password_policy(domain, state); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(result))); + goto done; + } + + } + +done: /* give us a more useful (more correct?) error code */ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || - (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { + (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { result = NT_STATUS_NO_LOGON_SERVERS; } @@ -439,8 +1224,8 @@ done: DOM_SID user_sid; fstring sidstr; - sid_copy(&user_sid, &info3.dom_sid.sid); - sid_append_rid(&user_sid, info3.user_rid); + sid_copy(&user_sid, &info3->dom_sid.sid); + sid_append_rid(&user_sid, info3->user_rid); sid_to_string(sidstr, &user_sid); afsname = talloc_string_sub(state->mem_ctx, afsname, "%s", sidstr); @@ -474,10 +1259,11 @@ done: no_token: talloc_free(afsname); } - + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } + /********************************************************************** Challenge Response Authentication Protocol **********************************************************************/ @@ -525,7 +1311,7 @@ void winbindd_pam_auth_crap(struct winbindd_cli_state *state) } if (domain_name != NULL) - domain = find_auth_domain(domain_name); + domain = find_auth_domain(state, domain_name); if (domain != NULL) { sendto_domain(state, domain); @@ -675,6 +1461,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, } while ( (attempts < 2) && retry ); if (NT_STATUS_IS_OK(result)) { + netsamlogon_cache_store(name_user, &info3); wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3); @@ -732,7 +1519,7 @@ done: /* give us a more useful (more correct?) error code */ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || - (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { + (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) { result = NT_STATUS_NO_LOGON_SERVERS; } @@ -763,12 +1550,16 @@ done: void winbindd_pam_chauthtok(struct winbindd_cli_state *state) { - NTSTATUS result; - char *oldpass, *newpass; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + char *oldpass; + char *newpass = NULL; fstring domain, user; POLICY_HND dom_pol; struct winbindd_domain *contact_domain; struct rpc_pipe_client *cli; + BOOL got_info = False; + SAM_UNK_INFO_1 *info; + SAMR_CHANGE_REJECT *reject; DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid, state->request.data.chauthtok.user)); @@ -798,10 +1589,70 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state) goto done; } - result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass, - oldpass); + result = rpccli_samr_chgpasswd3(cli, state->mem_ctx, user, newpass, oldpass, &info, &reject); + + /* FIXME: need to check for other error codes ? */ + if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) { + + state->response.data.auth.policy.min_length_password = + info->min_length_password; + state->response.data.auth.policy.password_history = + info->password_history; + state->response.data.auth.policy.password_properties = + info->password_properties; + state->response.data.auth.policy.expire = + nt_time_to_unix_abs(&info->expire); + state->response.data.auth.policy.min_passwordage = + nt_time_to_unix_abs(&info->min_passwordage); + + state->response.data.auth.reject_reason = + reject->reject_reason; + + got_info = True; + + } else if (!NT_STATUS_IS_OK(result)) { + + DEBUG(10,("Password change with chgpasswd3 failed with: %s, retrying chgpasswd_user\n", + nt_errstr(result))); + + state->response.data.auth.reject_reason = 0; + + result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass, oldpass); + } + +done: + if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) && + lp_winbind_offline_logon()) { + + NTSTATUS cred_ret; + + cred_ret = winbindd_update_creds_by_name(contact_domain, + state->mem_ctx, user, + newpass); + if (!NT_STATUS_IS_OK(cred_ret)) { + DEBUG(10,("Failed to store creds: %s\n", nt_errstr(cred_ret))); + goto process_result; /* FIXME: hm, risking inconsistant cache ? */ + } + } + + if (!NT_STATUS_IS_OK(result) && !got_info) { + + NTSTATUS policy_ret; + + policy_ret = fillup_password_policy(contact_domain, state); + + /* failure of this is non critical, it will just provide no + * additional information to the client why the change has + * failed - Guenther */ + + if (!NT_STATUS_IS_OK(policy_ret)) { + DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret))); + goto process_result; + } + } + +process_result: -done: state->response.data.auth.nt_status = NT_STATUS_V(result); fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result)); fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result)); @@ -819,3 +1670,112 @@ done: else request_error(state); } + +void winbindd_pam_logoff(struct winbindd_cli_state *state) +{ + struct winbindd_domain *domain; + fstring name_domain, user; + + DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid, + state->request.data.logoff.user)); + + /* Ensure null termination */ + state->request.data.logoff.user + [sizeof(state->request.data.logoff.user)-1]='\0'; + + state->request.data.logoff.krb5ccname + [sizeof(state->request.data.logoff.krb5ccname)-1]='\0'; + + parse_domain_user(state->request.data.logoff.user, name_domain, user); + + domain = find_auth_domain(state, name_domain); + + if (domain == NULL) { + set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER); + DEBUG(5, ("Pam Logoff for %s returned %s " + "(PAM: %d)\n", + state->request.data.auth.user, + state->response.data.auth.nt_status_string, + state->response.data.auth.pam_error)); + request_error(state); + return; + } + + sendto_domain(state, domain); +} + +enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + NTSTATUS result = NT_STATUS_NOT_SUPPORTED; + struct WINBINDD_CCACHE_ENTRY *entry; + int ret; + + DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid, + state->request.data.logoff.user)); + + if (!(state->request.flags & WBFLAG_PAM_KRB5)) { + result = NT_STATUS_OK; + goto process_result; + } + +#ifdef HAVE_KRB5 + + /* what we need here is to find the corresponding krb5 ccache name *we* + * created for a given username and destroy it (as the user who created it) */ + + entry = get_ccache_by_username(state->request.data.logoff.user); + if (entry == NULL) { + DEBUG(10,("winbindd_pam_logoff: could not get ccname for user %s\n", + state->request.data.logoff.user)); + goto process_result; + } + + DEBUG(10,("winbindd_pam_logoff: found ccache [%s]\n", entry->ccname)); + + if (entry->uid < 0 || state->request.data.logoff.uid < 0) { + DEBUG(0,("winbindd_pam_logoff: invalid uid\n")); + goto process_result; + } + + if (entry->uid != state->request.data.logoff.uid) { + DEBUG(0,("winbindd_pam_logoff: uid's differ: %d != %d\n", + entry->uid, state->request.data.logoff.uid)); + goto process_result; + } + + if (!strcsequal(entry->ccname, state->request.data.logoff.krb5ccname)) { + DEBUG(0,("winbindd_pam_logoff: krb5ccnames differ: (daemon) %s != (client) %s\n", + entry->ccname, state->request.data.logoff.krb5ccname)); + goto process_result; + } + + seteuid(entry->uid); + + ret = ads_kdestroy(entry->ccname); + + seteuid(0); + + if (ret) { + DEBUG(0,("winbindd_pam_logoff: failed to destroy user ccache %s with: %s\n", + entry->ccname, error_message(ret))); + } else { + DEBUG(10,("winbindd_pam_logoff: successfully destroyed ccache %s for user %s\n", + entry->ccname, state->request.data.logoff.user)); + remove_ccache_by_ccname(entry->ccname); + } + + result = krb5_to_nt_status(ret); +#else + result = NT_STATUS_NOT_SUPPORTED; +#endif + +process_result: + state->response.data.auth.nt_status = NT_STATUS_V(result); + fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result)); + fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result)); + state->response.data.auth.pam_error = nt_status_to_pam(result); + + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; +} + diff --git a/source/nsswitch/winbindd_passdb.c b/source/nsswitch/winbindd_passdb.c index c32aa01a38a..96a85a4f3a0 100644 --- a/source/nsswitch/winbindd_passdb.c +++ b/source/nsswitch/winbindd_passdb.c @@ -151,7 +151,8 @@ BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain, *gr_mem = NULL; *gr_mem_len = 0; - if (!pdb_enum_aliasmem(group_sid, &members, &num_members)) + if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members, + &num_members))) return True; for (i=0; iname); - *name = talloc_strdup(mem_ctx, info.acct_name); - if (sid_check_is_in_builtin(sid)) - *type = SID_NAME_WKN_GRP; - else - *type = SID_NAME_ALIAS; + if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) { + return NT_STATUS_NONE_MAPPED; + } + + *domain_name = talloc_strdup(mem_ctx, dom); + *name = talloc_strdup(mem_ctx, nam); return NT_STATUS_OK; } @@ -305,14 +311,14 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, uint32 num_sids, const DOM_SID *sids, uint32 *p_num_aliases, uint32 **rids) { - BOOL result; + NTSTATUS result; size_t num_aliases = 0; result = pdb_enum_alias_memberships(mem_ctx, &domain->sid, sids, num_sids, rids, &num_aliases); *p_num_aliases = num_aliases; - return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return result; } /* Lookup group membership given a rid. */ @@ -322,16 +328,106 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, DOM_SID **sid_mem, char ***names, uint32 **name_types) { + size_t i, num_members, num_mapped; + uint32 *rids; + NTSTATUS result; + const DOM_SID **sids; + struct lsa_dom_info *lsa_domains; + struct lsa_name_info *lsa_names; + + if (!sid_check_is_in_our_domain(group_sid)) { + /* There's no groups, only aliases in BUILTIN */ + return NT_STATUS_NO_SUCH_GROUP; + } + + result = pdb_enum_group_members(mem_ctx, group_sid, &rids, + &num_members); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + if (num_members == 0) { + *num_names = 0; + *sid_mem = NULL; + *names = NULL; + *name_types = NULL; + return NT_STATUS_OK; + } + + *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members); + *names = TALLOC_ARRAY(mem_ctx, char *, num_members); + *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members); + sids = TALLOC_ARRAY(mem_ctx, const DOM_SID *, num_members); + + if (((*sid_mem) == NULL) || ((*names) == NULL) || + ((*name_types) == NULL) || (sids == NULL)) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; isid); + sid_append_rid(sid, rids[i]); + sids[i] = sid; + } + + result = lookup_sids(mem_ctx, num_members, sids, 1, + &lsa_domains, &lsa_names); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + num_mapped = 0; + for (i=0; iname) == -1) { - return NT_STATUS_NO_MEMORY; - } - (*alt_names)[*num_domains] = NULL; - (*dom_sids)[*num_domains] = domains[i]->sid; - (*num_domains)++; - } - } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES)); + nt_status = secrets_trusted_domains(mem_ctx, num_domains, + &domains); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES)) { - return NT_STATUS_OK; + *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains); + *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains); + *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains); + + if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) { + return NT_STATUS_NO_MEMORY; } - return nt_status; + + for (i=0; i<*num_domains; i++) { + (*alt_names)[i] = NULL; + (*names)[i] = talloc_steal((*names), domains[i]->name); + sid_copy(&(*dom_sids)[i], &domains[i]->sid); + } + + return NT_STATUS_OK; } /* the rpc backend methods are exposed via this structure */ @@ -391,5 +481,7 @@ struct winbindd_methods passdb_methods = { lookup_useraliases, lookup_groupmem, sequence_number, + lockout_policy, + password_policy, trusted_domains, }; diff --git a/source/nsswitch/winbindd_reconnect.c b/source/nsswitch/winbindd_reconnect.c index 77df9c1513c..e37bfcad978 100644 --- a/source/nsswitch/winbindd_reconnect.c +++ b/source/nsswitch/winbindd_reconnect.c @@ -220,6 +220,36 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) return result; } +/* find the lockout policy of a domain */ +static NTSTATUS lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_12 *lockout_policy) +{ + NTSTATUS result; + + result = msrpc_methods.lockout_policy(domain, mem_ctx, lockout_policy); + + if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) + result = msrpc_methods.lockout_policy(domain, mem_ctx, lockout_policy); + + return result; +} + +/* find the password policy of a domain */ +static NTSTATUS password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_1 *password_policy) +{ + NTSTATUS result; + + result = msrpc_methods.password_policy(domain, mem_ctx, password_policy); + + if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) + result = msrpc_methods.password_policy(domain, mem_ctx, password_policy); + + return result; +} + /* get a list of trusted domains */ static NTSTATUS trusted_domains(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, @@ -255,5 +285,7 @@ struct winbindd_methods reconnect_methods = { lookup_useraliases, lookup_groupmem, sequence_number, + lockout_policy, + password_policy, trusted_domains, }; diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c index 6179189e309..4aaedad4a21 100644 --- a/source/nsswitch/winbindd_rpc.c +++ b/source/nsswitch/winbindd_rpc.c @@ -269,7 +269,7 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, return result; result = rpccli_lsa_lookup_names(cli, mem_ctx, &lsa_policy, 1, - &full_name, &sids, &types); + &full_name, NULL, &sids, &types); if (!NT_STATUS_IS_OK(result)) return result; @@ -883,6 +883,71 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, return result; } +/* find the lockout policy for a domain */ +NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_12 *lockout_policy) +{ + NTSTATUS result; + struct rpc_pipe_client *cli; + POLICY_HND dom_pol; + SAM_UNK_CTR ctr; + + DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name)); + + result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 12, &ctr); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + *lockout_policy = ctr.info.inf12; + + DEBUG(10,("msrpc_lockout_policy: bad_attempt_lockout %d\n", + ctr.info.inf12.bad_attempt_lockout)); + + done: + + return result; +} + +/* find the password policy for a domain */ +NTSTATUS msrpc_password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_1 *password_policy) +{ + NTSTATUS result; + struct rpc_pipe_client *cli; + POLICY_HND dom_pol; + SAM_UNK_CTR ctr; + + DEBUG(10,("rpc: fetch password policy for %s\n", domain->name)); + + result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 1, &ctr); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + *password_policy = ctr.info.inf1; + + DEBUG(10,("msrpc_password_policy: min_length_password %d\n", + ctr.info.inf1.min_length_password)); + + done: + + return result; +} + + /* the rpc backend methods are exposed via this structure */ struct winbindd_methods msrpc_methods = { False, @@ -896,5 +961,7 @@ struct winbindd_methods msrpc_methods = { msrpc_lookup_useraliases, lookup_groupmem, sequence_number, + msrpc_lockout_policy, + msrpc_password_policy, trusted_domains, }; diff --git a/source/nsswitch/winbindd_sid.c b/source/nsswitch/winbindd_sid.c index fc878cb5ccb..a4cd8f76042 100644 --- a/source/nsswitch/winbindd_sid.c +++ b/source/nsswitch/winbindd_sid.c @@ -506,10 +506,10 @@ static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success) request_ok(state->cli_state); } -void winbindd_allocate_rid(struct winbindd_cli_state *state) +void winbindd_allocate_uid(struct winbindd_cli_state *state) { if ( !state->privileged ) { - DEBUG(2, ("winbindd_allocate_rid: non-privileged access " + DEBUG(2, ("winbindd_allocate_uid: non-privileged access " "denied!\n")); request_error(state); return; @@ -518,25 +518,22 @@ void winbindd_allocate_rid(struct winbindd_cli_state *state) sendto_child(state, idmap_child()); } -enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain, +enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain, struct winbindd_cli_state *state) { - /* We tell idmap to always allocate a user RID. There might be a good - * reason to keep RID allocation for users to even and groups to - * odd. This needs discussion I think. For now only allocate user - * rids. */ + union unid_t id; - if (!NT_STATUS_IS_OK(idmap_allocate_rid(&state->response.data.rid, - USER_RID_TYPE))) + if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_USERID))) { return WINBINDD_ERROR; - + } + state->response.data.uid = id.uid; return WINBINDD_OK; } -void winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state) +void winbindd_allocate_gid(struct winbindd_cli_state *state) { if ( !state->privileged ) { - DEBUG(2, ("winbindd_allocate_rid: non-privileged access " + DEBUG(2, ("winbindd_allocate_gid: non-privileged access " "denied!\n")); request_error(state); return; @@ -545,30 +542,15 @@ void winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state) sendto_child(state, idmap_child()); } -enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain, - struct winbindd_cli_state *state) +enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain, + struct winbindd_cli_state *state) { - NTSTATUS result; - DOM_SID sid; - - /* We tell idmap to always allocate a user RID. This is really - * historic and needs to be fixed. I *think* this has to do with the - * way winbind determines its free RID space. */ - - result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid, - USER_RID_TYPE); + union unid_t id; - if (!NT_STATUS_IS_OK(result)) + if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_GROUPID))) { return WINBINDD_ERROR; - - sid_copy(&sid, get_global_sam_sid()); - sid_append_rid(&sid, state->response.data.rid_and_gid.rid); - - result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid, - 0); - - if (!NT_STATUS_IS_OK(result)) - return WINBINDD_ERROR; - + } + state->response.data.gid = id.gid; return WINBINDD_OK; } + diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c index 0b88d5eee5f..9670bf534cb 100644 --- a/source/nsswitch/winbindd_user.c +++ b/source/nsswitch/winbindd_user.c @@ -122,10 +122,10 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, pw->pw_uid, pw->pw_gid, shell, pw->pw_shell)) return False; - /* Password - set to "x" as we can't generate anything useful here. + /* Password - set to "*" as we can't generate anything useful here. Authentication can be done using the pam_winbind module. */ - safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1); + safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1); return True; } @@ -307,10 +307,10 @@ static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid) goto failed; } - /* Password - set to "x" as we can't generate anything useful here. + /* Password - set to "*" as we can't generate anything useful here. Authentication can be done using the pam_winbind module. */ - safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1); + safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1); request_ok(s->state); return; diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index 4c3306a8aca..b92ee0de825 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -161,6 +161,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const domain->sequence_number = DOM_SEQUENCE_NONE; domain->last_seq_check = 0; domain->initialized = False; + domain->online = False; if (sid) { sid_copy(&domain->sid, sid); } @@ -334,6 +335,7 @@ enum winbindd_result init_child_connection(struct winbindd_domain *domain, struct winbindd_request *request; struct winbindd_response *response; struct init_child_state *state; + struct winbindd_domain *request_domain; mem_ctx = talloc_init("init_child_connection"); if (mem_ctx == NULL) { @@ -366,7 +368,6 @@ enum winbindd_result init_child_connection(struct winbindd_domain *domain, fstrcpy(request->domain_name, domain->name); request->data.init_conn.is_primary = True; fstrcpy(request->data.init_conn.dcname, ""); - async_request(mem_ctx, &domain->child, request, response, init_child_recv, state); return WINBINDD_PENDING; @@ -378,7 +379,11 @@ enum winbindd_result init_child_connection(struct winbindd_domain *domain, request->cmd = WINBINDD_GETDCNAME; fstrcpy(request->domain_name, domain->name); - async_domain_request(mem_ctx, find_our_domain(), request, response, + /* save online flag */ + request_domain = find_our_domain(); + request_domain->online = domain->online; + + async_domain_request(mem_ctx, request_domain, request, response, init_child_getdc_recv, state); return WINBINDD_PENDING; } @@ -1079,10 +1084,6 @@ static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state #define HWM_GROUP "GROUP HWM" #define HWM_USER "USER HWM" -/* idmap version determines auto-conversion */ -#define IDMAP_VERSION 2 - - /***************************************************************************** Convert the idmap database from an older version. *****************************************************************************/ diff --git a/source/pam_smbpass/pam_smb_auth.c b/source/pam_smbpass/pam_smb_auth.c index 70275abf922..cbdb6fa8116 100644 --- a/source/pam_smbpass/pam_smb_auth.c +++ b/source/pam_smbpass/pam_smb_auth.c @@ -199,10 +199,10 @@ static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, /* Add the user to the db if they aren't already there. */ if (!exist) { - retval = local_password_change( name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD, + retval = NT_STATUS_IS_OK(local_password_change( name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD, pass, err_str, sizeof(err_str), - msg_str, sizeof(msg_str) ); + msg_str, sizeof(msg_str) )); if (!retval && *err_str) { err_str[PSTRING_LEN-1] = '\0'; @@ -221,8 +221,8 @@ static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, /* mimick 'update encrypted' as long as the 'no pw req' flag is not set */ if ( pdb_get_acct_ctrl(sampass) & ~ACB_PWNOTREQ ) { - retval = local_password_change( name, LOCAL_SET_PASSWORD, pass, err_str, sizeof(err_str), - msg_str, sizeof(msg_str) ); + retval = NT_STATUS_IS_OK(local_password_change( name, LOCAL_SET_PASSWORD, pass, err_str, sizeof(err_str), + msg_str, sizeof(msg_str) )); if (!retval && *err_str) { err_str[PSTRING_LEN-1] = '\0'; diff --git a/source/pam_smbpass/pam_smb_passwd.c b/source/pam_smbpass/pam_smb_passwd.c index 8149bc12003..176b278c043 100644 --- a/source/pam_smbpass/pam_smb_passwd.c +++ b/source/pam_smbpass/pam_smb_passwd.c @@ -47,9 +47,9 @@ int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user, const char * err_str[0] = '\0'; msg_str[0] = '\0'; - retval = local_password_change( user, LOCAL_SET_PASSWORD, pass_new, + retval = NT_STATUS_IS_OK(local_password_change( user, LOCAL_SET_PASSWORD, pass_new, err_str, sizeof(err_str), - msg_str, sizeof(msg_str) ); + msg_str, sizeof(msg_str) )); if (!retval) { if (*err_str) { @@ -298,7 +298,7 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags, uid_t uid; /* password updated */ - if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sampass), &uid))) { + if (!sid_to_uid(pdb_get_user_sid(sampass), &uid)) { _log_err( LOG_NOTICE, "Unable to get uid for user %s", pdb_get_username(sampass)); _log_err( LOG_NOTICE, "password for (%s) changed by (%s/%d)", diff --git a/source/pam_smbpass/support.c b/source/pam_smbpass/support.c index 3f2c6388160..add74acc5da 100644 --- a/source/pam_smbpass/support.c +++ b/source/pam_smbpass/support.c @@ -398,7 +398,7 @@ int _smb_verify_password( pam_handle_t * pamh, SAM_ACCOUNT *sampass, service ? service : "**unknown**", name); newauth->count = 1; } - if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id)))) { + if (!sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id))) { _log_err(LOG_NOTICE, "failed auth request by %s for service %s as %s", uidtoname(getuid()), diff --git a/source/param/loadparm.c b/source/param/loadparm.c index a2aa851b095..a8867280474 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -54,6 +54,7 @@ #include "includes.h" BOOL in_client = False; /* Not in the client by default */ +BOOL in_server = False; /* Not in the server by default */ BOOL bLoaded = False; extern userdom_struct current_user_info; @@ -76,6 +77,9 @@ extern enum protocol_types Protocol; #define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && (ServicePtrs != NULL) && ServicePtrs[(i)]->valid) #define VALID(i) (ServicePtrs != NULL && ServicePtrs[i]->valid) +#define USERSHARE_VALID 1 +#define USERSHARE_PENDING_DELETE 2 + int keepalive = DEFAULT_KEEPALIVE; BOOL use_getwd_cache = True; @@ -94,8 +98,7 @@ struct _param_opt_struct { /* * This structure describes global (ie., server-wide) parameters. */ -typedef struct -{ +typedef struct { char *smb_ports; char *dos_charset; char *unix_charset; @@ -167,7 +170,6 @@ typedef struct BOOL bUtmp; char *szIdmapUID; char *szIdmapGID; - BOOL bEnableRidAlgorithm; BOOL bPassdbExpandExplicit; int AlgorithmicRidBase; char *szTemplateHomedir; @@ -178,6 +180,8 @@ typedef struct BOOL bWinbindUseDefaultDomain; BOOL bWinbindTrustedDomainsOnly; BOOL bWinbindNestedGroups; + BOOL bWinbindRefreshTickets; + BOOL bWinbindOfflineLogon; char **szIdmapBackend; char *szAddShareCommand; char *szChangeShareCommand; @@ -186,6 +190,10 @@ typedef struct char *szGuestaccount; char *szManglingMethod; char **szServicesList; + char *szUsersharePath; + char *szUsershareTemplateShare; + char **szUsersharePrefixAllowList; + char **szUsersharePrefixDenyList; int mangle_prefix; int max_log_size; char *szLogLevel; @@ -299,24 +307,27 @@ typedef struct BOOL bDeferSharingViolations; BOOL bEnablePrivileges; BOOL bASUSupport; + BOOL bUsershareOwnerOnly; int restrict_anonymous; int name_cache_timeout; int client_signing; int server_signing; + int iUsershareMaxShares; + BOOL bResetOnZeroVC; param_opt_struct *param_opt; -} -global; +} global; static global Globals; /* * This structure describes a single service. */ -typedef struct -{ +typedef struct { BOOL valid; BOOL autoloaded; + int usershare; + time_t usershare_last_mod; char *szService; char *szPath; char *szUsername; @@ -445,14 +456,15 @@ typedef struct param_opt_struct *param_opt; char dummy[3]; /* for alignment */ -} -service; +} service; /* This is a default service used to prime a services structure */ static service sDefault = { True, /* valid */ False, /* not autoloaded */ + 0, /* not a usershare */ + (time_t)0, /* No last mod time */ NULL, /* szService */ NULL, /* szPath */ NULL, /* szUsername */ @@ -1214,6 +1226,12 @@ static struct parm_struct parm_table[] = { {"root preexec close", P_BOOL, P_LOCAL, &sDefault.bRootpreexecClose, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, + {"usershare max shares", P_INTEGER, P_GLOBAL, &Globals.iUsershareMaxShares, NULL, NULL, FLAG_ADVANCED}, + {"usershare owner only", P_BOOL, P_GLOBAL, &Globals.bUsershareOwnerOnly, NULL, NULL, FLAG_ADVANCED}, + {"usershare path", P_STRING, P_GLOBAL, &Globals.szUsersharePath, NULL, NULL, FLAG_ADVANCED}, + {"usershare prefix allow list", P_LIST, P_GLOBAL, &Globals.szUsersharePrefixAllowList, NULL, NULL, FLAG_ADVANCED}, + {"usershare prefix deny list", P_LIST, P_GLOBAL, &Globals.szUsersharePrefixDenyList, NULL, NULL, FLAG_ADVANCED}, + {"usershare template share", P_STRING, P_GLOBAL, &Globals.szUsershareTemplateShare, NULL, NULL, FLAG_ADVANCED}, {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE }, {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, @@ -1242,7 +1260,6 @@ static struct parm_struct parm_table[] = { {N_("Winbind options"), P_SEP, P_SEPARATOR}, - {"enable rid algorithm", P_BOOL, P_GLOBAL, &Globals.bEnableRidAlgorithm, NULL, NULL, FLAG_DEPRECATED}, {"passdb expand explicit", P_BOOL, P_GLOBAL, &Globals.bPassdbExpandExplicit, NULL, NULL, FLAG_ADVANCED}, {"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED}, {"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED}, @@ -1260,6 +1277,8 @@ static struct parm_struct parm_table[] = { {"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED}, {"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED}, {"winbind nss info", P_LIST, P_GLOBAL, &Globals.szWinbindNssInfo, NULL, NULL, FLAG_ADVANCED}, + {"winbind refresh tickets", P_BOOL, P_GLOBAL, &Globals.bWinbindRefreshTickets, NULL, NULL, FLAG_ADVANCED}, + {"winbind offline logon", P_BOOL, P_GLOBAL, &Globals.bWinbindOfflineLogon, NULL, NULL, FLAG_ADVANCED}, {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0} }; @@ -1612,8 +1631,9 @@ static void init_globals(BOOL first_time_only) Globals.bWinbindNestedGroups = False; Globals.winbind_max_idle_children = 3; Globals.szWinbindNssInfo = str_list_make("template", NULL); + Globals.bWinbindRefreshTickets = False; + Globals.bWinbindOfflineLogon = False; - Globals.bEnableRidAlgorithm = True; Globals.bPassdbExpandExplicit = True; Globals.name_cache_timeout = 660; /* In seconds */ @@ -1636,6 +1656,15 @@ static void init_globals(BOOL first_time_only) Globals.bASUSupport = True; Globals.szServicesList = str_list_make( "Spooler NETLOGON", NULL ); + + /* User defined shares. */ + pstrcpy(s, dyn_LOCKDIR); + pstrcat(s, "/usershares"); + string_set(&Globals.szUsersharePath, s); + string_set(&Globals.szUsershareTemplateShare, ""); + Globals.iUsershareMaxShares = 0; + /* By default disallow sharing of directories not owned by the sharer. */ + Globals.bUsershareOwnerOnly = True; } static TALLOC_CTX *lp_talloc; @@ -1652,6 +1681,19 @@ void lp_talloc_free(void) lp_talloc = NULL; } +TALLOC_CTX *tmp_talloc_ctx(void) +{ + if (lp_talloc == NULL) { + lp_talloc = talloc_init(NULL); + } + + if (lp_talloc == NULL) { + smb_panic("Could not create temporary talloc context\n"); + } + + return lp_talloc; +} + /******************************************************************* Convenience routine to grab string parameters into temporary memory and run standard_sub_basic on them. The buffers can be written to by @@ -1800,10 +1842,10 @@ FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups) FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain) FN_GLOBAL_BOOL(lp_winbind_trusted_domains_only, &Globals.bWinbindTrustedDomainsOnly) FN_GLOBAL_BOOL(lp_winbind_nested_groups, &Globals.bWinbindNestedGroups) - +FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets) +FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon) FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend) -FN_GLOBAL_BOOL(lp_enable_rid_algorithm, &Globals.bEnableRidAlgorithm) FN_GLOBAL_BOOL(lp_passdb_expand_explicit, &Globals.bPassdbExpandExplicit) #ifdef WITH_LDAP_SAMCONFIG @@ -1821,9 +1863,13 @@ FN_GLOBAL_INTEGER(lp_ldap_page_size, &Globals.ldap_page_size) FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand) FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand) FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand) +FN_GLOBAL_STRING(lp_usershare_path, &Globals.szUsersharePath) +FN_GLOBAL_LIST(lp_usershare_prefix_allow_list, &Globals.szUsersharePrefixAllowList) +FN_GLOBAL_LIST(lp_usershare_prefix_deny_list, &Globals.szUsersharePrefixDenyList) FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs) +FN_GLOBAL_BOOL(lp_usershare_owner_only, &Globals.bUsershareOwnerOnly) FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios) FN_GLOBAL_BOOL(lp_reset_on_zero_vc, &Globals.bResetOnZeroVC) FN_GLOBAL_BOOL(lp_ms_add_printer_wizard, &Globals.bMsAddPrinterWizard) @@ -1912,6 +1958,8 @@ FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest) FN_GLOBAL_INTEGER(lp_oplock_break_wait_time, &Globals.oplock_break_wait_time) FN_GLOBAL_INTEGER(lp_lock_spin_count, &Globals.iLockSpinCount) FN_GLOBAL_INTEGER(lp_lock_sleep_time, &Globals.iLockSpinTime) +FN_GLOBAL_INTEGER(lp_usershare_max_shares, &Globals.iUsershareMaxShares) + FN_LOCAL_STRING(lp_preexec, szPreExec) FN_LOCAL_STRING(lp_postexec, szPostExec) FN_LOCAL_STRING(lp_rootpreexec, szRootPreExec) @@ -2479,7 +2527,7 @@ static char *canonicalize_servicename(const char *src) } fstrcpy( canon, src ); - strupper_m( canon ); + strlower_m( canon ); return canon; } @@ -4028,9 +4076,11 @@ void lp_killunused(BOOL (*snumused) (int)) if (!VALID(i)) continue; - /* don't kill autoloaded services */ - if ( ServicePtrs[i]->autoloaded ) + /* don't kill autoloaded or usershare services */ + if ( ServicePtrs[i]->autoloaded || + ServicePtrs[i]->usershare == USERSHARE_VALID) { continue; + } if (!snumused || !snumused(i)) { free_service_byindex(i); @@ -4179,6 +4229,7 @@ static void set_server_role(void) /*********************************************************** If we should send plaintext/LANMAN passwords in the clinet ************************************************************/ + static void set_allowed_client_auth(void) { if (Globals.bClientNTLMv2Auth) { @@ -4189,6 +4240,611 @@ static void set_allowed_client_auth(void) } } +/*************************************************************************** + JRA. + The following code allows smbd to read a user defined share file. + Yes, this is my intent. Yes, I'm comfortable with that... + + THE FOLLOWING IS SECURITY CRITICAL CODE. + + It washes your clothes, it cleans your house, it guards you while you sleep... + Do not f%^k with it.... +***************************************************************************/ + +#define MAX_USERSHARE_FILE_SIZE (10*1024) + +/*************************************************************************** + Check allowed stat state of a usershare file. + Ensure we print out who is dicking with us so the admin can + get their sorry ass fired. +***************************************************************************/ + +static BOOL check_usershare_stat(const char *fname, SMB_STRUCT_STAT *psbuf) +{ + if (!S_ISREG(psbuf->st_mode)) { + DEBUG(0,("check_usershare_stat: file %s owned by uid %u is " + "not a regular file\n", + fname, (unsigned int)psbuf->st_uid )); + return False; + } + + /* Ensure this doesn't have the other write bit set. */ + if (psbuf->st_mode & S_IWOTH) { + DEBUG(0,("check_usershare_stat: file %s owned by uid %u allows " + "public write. Refusing to allow as a usershare file.\n", + fname, (unsigned int)psbuf->st_uid )); + return False; + } + + /* Should be 10k or less. */ + if (psbuf->st_size > MAX_USERSHARE_FILE_SIZE) { + DEBUG(0,("check_usershare_stat: file %s owned by uid %u is " + "too large (%u) to be a user share file.\n", + fname, (unsigned int)psbuf->st_uid, + (unsigned int)psbuf->st_size )); + return False; + } + + return True; +} + +/*************************************************************************** + Parse the contents of a usershare file. +***************************************************************************/ + +enum usershare_err parse_usershare_file(TALLOC_CTX *ctx, + SMB_STRUCT_STAT *psbuf, + const char *servicename, + int snum, + char **lines, + int numlines, + pstring sharepath, + pstring comment, + SEC_DESC **ppsd) +{ + const char **prefixallowlist = lp_usershare_prefix_allow_list(); + const char **prefixdenylist = lp_usershare_prefix_deny_list(); + SMB_STRUCT_DIR *dp; + SMB_STRUCT_STAT sbuf; + + if (numlines < 4) { + return USERSHARE_MALFORMED_FILE; + } + + if (!strequal(lines[0], "#VERSION 1")) { + return USERSHARE_BAD_VERSION; + } + + if (!strnequal(lines[1], "path=", 5)) { + return USERSHARE_MALFORMED_PATH; + } + + pstrcpy(sharepath, &lines[1][5]); + trim_string(sharepath, " ", " "); + + if (!strnequal(lines[2], "comment=", 8)) { + return USERSHARE_MALFORMED_COMMENT_DEF; + } + + pstrcpy(comment, &lines[2][8]); + trim_string(comment, " ", " "); + trim_char(comment, '"', '"'); + + if (!strnequal(lines[3], "usershare_acl=", 14)) { + return USERSHARE_MALFORMED_ACL_DEF; + } + + if (!parse_usershare_acl(ctx, &lines[3][14], ppsd)) { + return USERSHARE_ACL_ERR; + } + + if (snum != -1 && strequal(sharepath, ServicePtrs[snum]->szPath)) { + /* Path didn't change, no checks needed. */ + return USERSHARE_OK; + } + + /* The path *must* be absolute. */ + if (sharepath[0] != '/') { + DEBUG(2,("parse_usershare_file: share %s: path %s is not an absolute path.\n", + servicename, sharepath)); + return USERSHARE_PATH_NOT_ABSOLUTE; + } + + /* If there is a usershare prefix deny list ensure one of these paths + doesn't match the start of the user given path. */ + if (prefixdenylist) { + int i; + for ( i=0; prefixdenylist[i]; i++ ) { + DEBUG(10,("parse_usershare_file: share %s : checking prefixdenylist[%d]='%s' against %s\n", + servicename, i, prefixdenylist[i], sharepath )); + if (memcmp( sharepath, prefixdenylist[i], strlen(prefixdenylist[i])) == 0) { + DEBUG(2,("parse_usershare_file: share %s path %s starts with one of the " + "usershare prefix deny list entries.\n", + servicename, sharepath)); + return USERSHARE_PATH_IS_DENIED; + } + } + } + + /* If there is a usershare prefix allow list ensure one of these paths + does match the start of the user given path. */ + + if (prefixallowlist) { + int i; + for ( i=0; prefixallowlist[i]; i++ ) { + DEBUG(10,("parse_usershare_file: share %s checking prefixallowlist[%d]='%s' against %s\n", + servicename, i, prefixallowlist[i], sharepath )); + if (memcmp( sharepath, prefixallowlist[i], strlen(prefixallowlist[i])) == 0) { + break; + } + } + if (prefixallowlist[i] == NULL) { + DEBUG(2,("parse_usershare_file: share %s path %s doesn't start with one of the " + "usershare prefix allow list entries.\n", + servicename, sharepath)); + return USERSHARE_PATH_NOT_ALLOWED; + } + } + + /* Ensure this is pointing to a directory. */ + dp = sys_opendir(sharepath); + + if (!dp) { + DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n", + servicename, sharepath)); + return USERSHARE_PATH_NOT_DIRECTORY; + } + + /* Ensure the owner of the usershare file has permission to share + this directory. */ + + if (sys_stat(sharepath, &sbuf) == -1) { + DEBUG(2,("parse_usershare_file: share %s : stat failed on path %s. %s\n", + servicename, sharepath, strerror(errno) )); + sys_closedir(dp); + return USERSHARE_POSIX_ERR; + } + + sys_closedir(dp); + + if (!S_ISDIR(sbuf.st_mode)) { + DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n", + servicename, sharepath )); + return USERSHARE_PATH_NOT_DIRECTORY; + } + + /* Check if sharing is restricted to owner-only. */ + /* psbuf is the stat of the usershare definition file, + sbuf is the stat of the target directory to be shared. */ + + if (lp_usershare_owner_only()) { + /* root can share anything. */ + if ((psbuf->st_uid != 0) && (sbuf.st_uid != psbuf->st_uid)) { + return USERSHARE_PATH_NOT_ALLOWED; + } + } + + return USERSHARE_OK; +} + +/*************************************************************************** + Deal with a usershare file. + Returns: + >= 0 - snum + -1 - Bad name, invalid contents. + - service name already existed and not a usershare, problem + with permissions to share directory etc. +***************************************************************************/ + +static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template) +{ + SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT lsbuf; + pstring fname; + pstring sharepath; + pstring comment; + fstring service_name; + char **lines = NULL; + int numlines = 0; + int fd = -1; + int iService = -1; + TALLOC_CTX *ctx = NULL; + SEC_DESC *psd = NULL; + + /* Ensure share name doesn't contain invalid characters. */ + if (!validate_net_name(file_name, INVALID_SHARENAME_CHARS, strlen(file_name))) { + DEBUG(0,("process_usershare_file: share name %s contains " + "invalid characters (any of %s)\n", + file_name, INVALID_SHARENAME_CHARS )); + return -1; + } + + fstrcpy(service_name, file_name); + + pstrcpy(fname, dir_name); + pstrcat(fname, "/"); + pstrcat(fname, file_name); + + /* Minimize the race condition by doing an lstat before we + open and fstat. Ensure this isn't a symlink link. */ + + if (sys_lstat(fname, &lsbuf) != 0) { + DEBUG(0,("process_usershare_file: stat of %s failed. %s\n", + fname, strerror(errno) )); + return -1; + } + + /* This must be a regular file, not a symlink, directory or + other strange filetype. */ + if (!check_usershare_stat(fname, &lsbuf)) { + return -1; + } + + /* See if there is already a servicenum for this name. */ + /* tdb_fetch_int32 returns -1 if not found. */ + iService = (int)tdb_fetch_int32(ServiceHash, canonicalize_servicename(service_name) ); + + if (iService != -1 && ServicePtrs[iService]->usershare_last_mod == lsbuf.st_mtime) { + /* Nothing changed - Mark valid and return. */ + DEBUG(10,("process_usershare_file: service %s not changed.\n", + service_name )); + ServicePtrs[iService]->usershare = USERSHARE_VALID; + return iService; + } + + /* Try and open the file read only - no symlinks allowed. */ +#ifdef O_NOFOLLOW + fd = sys_open(fname, O_RDONLY|O_NOFOLLOW, 0); +#else + fd = sys_open(fname, O_RDONLY, 0); +#endif + + if (fd == -1) { + DEBUG(0,("process_usershare_file: unable to open %s. %s\n", + fname, strerror(errno) )); + return -1; + } + + /* Now fstat to be *SURE* it's a regular file. */ + if (sys_fstat(fd, &sbuf) != 0) { + close(fd); + DEBUG(0,("process_usershare_file: fstat of %s failed. %s\n", + fname, strerror(errno) )); + return -1; + } + + /* Is it the same dev/inode as was lstated ? */ + if (lsbuf.st_dev != sbuf.st_dev || lsbuf.st_ino != sbuf.st_ino) { + close(fd); + DEBUG(0,("process_usershare_file: fstat of %s is a different file from lstat. " + "Symlink spoofing going on ?\n", fname )); + return -1; + } + + /* This must be a regular file, not a symlink, directory or + other strange filetype. */ + if (!check_usershare_stat(fname, &sbuf)) { + return -1; + } + + lines = fd_lines_load(fd, &numlines, MAX_USERSHARE_FILE_SIZE); + + close(fd); + if (lines == NULL) { + DEBUG(0,("process_usershare_file: loading file %s owned by %u failed.\n", + fname, (unsigned int)sbuf.st_uid )); + } + + /* Should we allow printers to be shared... ? */ + ctx = talloc_init("usershare_sd_xctx"); + if (!ctx) { + SAFE_FREE(lines); + return 1; + } + + if (parse_usershare_file(ctx, &sbuf, service_name, iService, lines, numlines, sharepath, comment, &psd) != USERSHARE_OK) { + talloc_destroy(ctx); + SAFE_FREE(lines); + return -1; + } + + SAFE_FREE(lines); + + /* Everything ok - add the service possibly using a template. */ + if (iService < 0) { + const service *sp = &sDefault; + if (snum_template != -1) { + sp = ServicePtrs[snum_template]; + } + + if ((iService = add_a_service(sp, service_name)) < 0) { + DEBUG(0, ("process_usershare_file: Failed to add " + "new service %s\n", service_name)); + talloc_destroy(ctx); + return -1; + } + + /* Read only is controlled by usershare ACL below. */ + ServicePtrs[iService]->bRead_only = False; + } + + /* Write the ACL of the new/modified share. */ + if (!set_share_security(ctx, service_name, psd)) { + DEBUG(0, ("process_usershare_file: Failed to set share " + "security for user share %s\n", + service_name )); + lp_remove_service(iService); + talloc_destroy(ctx); + return -1; + } + + talloc_destroy(ctx); + + /* If from a template it may be marked invalid. */ + ServicePtrs[iService]->valid = True; + + /* Set the service as a valid usershare. */ + ServicePtrs[iService]->usershare = USERSHARE_VALID; + + /* And note when it was loaded. */ + ServicePtrs[iService]->usershare_last_mod = sbuf.st_mtime; + string_set(&ServicePtrs[iService]->szPath, sharepath); + string_set(&ServicePtrs[iService]->comment, comment); + + return iService; +} + +/*************************************************************************** + Checks if a usershare entry has been modified since last load. +***************************************************************************/ + +static BOOL usershare_exists(int iService, time_t *last_mod) +{ + SMB_STRUCT_STAT lsbuf; + const char *usersharepath = Globals.szUsersharePath; + pstring fname; + + pstrcpy(fname, usersharepath); + pstrcat(fname, "/"); + pstrcat(fname, ServicePtrs[iService]->szService); + + if (sys_lstat(fname, &lsbuf) != 0) { + return False; + } + + if (!S_ISREG(lsbuf.st_mode)) { + return False; + } + + *last_mod = lsbuf.st_mtime; + return True; +} + +/*************************************************************************** + Load a usershare service by name. Returns a valid servicenumber or -1. +***************************************************************************/ + +int load_usershare_service(const char *servicename) +{ + SMB_STRUCT_STAT sbuf; + const char *usersharepath = Globals.szUsersharePath; + int max_user_shares = Globals.iUsershareMaxShares; + int snum_template = -1; + + if (*usersharepath == 0 || max_user_shares == 0) { + return -1; + } + + if (sys_stat(usersharepath, &sbuf) != 0) { + DEBUG(0,("load_usershare_service: stat of %s failed. %s\n", + usersharepath, strerror(errno) )); + return -1; + } + + if (!S_ISDIR(sbuf.st_mode)) { + DEBUG(0,("load_usershare_service: %s is not a directory.\n", + usersharepath )); + return -1; + } + + /* + * This directory must be owned by root, and have the 't' bit set. + * It also must not be writable by "other". + */ + +#ifdef S_ISVTX + if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) { +#else + if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) { +#endif + DEBUG(0,("load_usershare_service: directory %s is not owned by root " + "or does not have the sticky bit 't' set or is writable by anyone.\n", + usersharepath )); + return -1; + } + + /* Ensure the template share exists if it's set. */ + if (Globals.szUsershareTemplateShare[0]) { + /* We can't use lp_servicenumber here as we are recommending that + template shares have -valid=False set. */ + for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) { + if (ServicePtrs[snum_template]->szService && + strequal(ServicePtrs[snum_template]->szService, + Globals.szUsershareTemplateShare)) { + break; + } + } + + if (snum_template == -1) { + DEBUG(0,("load_usershare_service: usershare template share %s " + "does not exist.\n", + Globals.szUsershareTemplateShare )); + return -1; + } + } + + return process_usershare_file(usersharepath, servicename, snum_template); +} + +/*************************************************************************** + Load all user defined shares from the user share directory. + We only do this if we're enumerating the share list. + This is the function that can delete usershares that have + been removed. +***************************************************************************/ + +int load_usershare_shares(void) +{ + SMB_STRUCT_DIR *dp; + SMB_STRUCT_STAT sbuf; + SMB_STRUCT_DIRENT *de; + int num_usershares = 0; + int max_user_shares = Globals.iUsershareMaxShares; + unsigned int num_dir_entries, num_bad_dir_entries, num_tmp_dir_entries; + unsigned int allowed_bad_entries = ((2*max_user_shares)/10); + unsigned int allowed_tmp_entries = ((2*max_user_shares)/10); + int iService; + int snum_template = -1; + const char *usersharepath = Globals.szUsersharePath; + int ret = lp_numservices(); + + if (max_user_shares == 0 || *usersharepath == '\0') { + return lp_numservices(); + } + + if (sys_stat(usersharepath, &sbuf) != 0) { + DEBUG(0,("load_usershare_shares: stat of %s failed. %s\n", + usersharepath, strerror(errno) )); + return ret; + } + + /* + * This directory must be owned by root, and have the 't' bit set. + * It also must not be writable by "other". + */ + +#ifdef S_ISVTX + if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) { +#else + if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) { +#endif + DEBUG(0,("load_usershare_shares: directory %s is not owned by root " + "or does not have the sticky bit 't' set or is writable by anyone.\n", + usersharepath )); + return ret; + } + + /* Ensure the template share exists if it's set. */ + if (Globals.szUsershareTemplateShare[0]) { + /* We can't use lp_servicenumber here as we are recommending that + template shares have -valid=False set. */ + for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) { + if (ServicePtrs[snum_template]->szService && + strequal(ServicePtrs[snum_template]->szService, + Globals.szUsershareTemplateShare)) { + break; + } + } + + if (snum_template == -1) { + DEBUG(0,("load_usershare_shares: usershare template share %s " + "does not exist.\n", + Globals.szUsershareTemplateShare )); + return ret; + } + } + + /* Mark all existing usershares as pending delete. */ + for (iService = iNumServices - 1; iService >= 0; iService--) { + if (VALID(iService) && ServicePtrs[iService]->usershare) { + ServicePtrs[iService]->usershare = USERSHARE_PENDING_DELETE; + } + } + + dp = sys_opendir(usersharepath); + if (!dp) { + DEBUG(0,("load_usershare_shares:: failed to open directory %s. %s\n", + usersharepath, strerror(errno) )); + return ret; + } + + for (num_dir_entries = 0, num_bad_dir_entries = 0, num_tmp_dir_entries = 0; + (de = sys_readdir(dp)); + num_dir_entries++ ) { + int r; + const char *n = de->d_name; + + /* Ignore . and .. */ + if (*n == '.') { + if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) { + continue; + } + } + + if (n[0] == ':') { + /* Temporary file used when creating a share. */ + num_tmp_dir_entries++; + } + + /* Allow 20% tmp entries. */ + if (num_tmp_dir_entries > allowed_tmp_entries) { + DEBUG(0,("load_usershare_shares: too many temp entries (%u) " + "in directory %s\n", + num_tmp_dir_entries, usersharepath)); + break; + } + + r = process_usershare_file(usersharepath, n, snum_template); + if (r == 0) { + /* Update the services count. */ + num_usershares++; + if (num_usershares >= max_user_shares) { + DEBUG(0,("load_usershare_shares: max user shares reached " + "on file %s in directory %s\n", + n, usersharepath )); + break; + } + } else if (r == -1) { + num_bad_dir_entries++; + } + + /* Allow 20% bad entries. */ + if (num_bad_dir_entries > allowed_bad_entries) { + DEBUG(0,("load_usershare_shares: too many bad entries (%u) " + "in directory %s\n", + num_bad_dir_entries, usersharepath)); + break; + } + + /* Allow 20% bad entries. */ + if (num_dir_entries > max_user_shares + allowed_bad_entries) { + DEBUG(0,("load_usershare_shares: too many total entries (%u) " + "in directory %s\n", + num_dir_entries, usersharepath)); + break; + } + } + + sys_closedir(dp); + + /* Sweep through and delete any non-refreshed usershares that are + not currently in use. */ + for (iService = iNumServices - 1; iService >= 0; iService--) { + if (VALID(iService) && (ServicePtrs[iService]->usershare == USERSHARE_PENDING_DELETE)) { + if (conn_snum_used(iService)) { + continue; + } + /* Remove from the share ACL db. */ + DEBUG(10,("load_usershare_shares: Removing deleted usershare %s\n", + lp_servicename(iService) )); + delete_share_security(iService); + free_service_byindex(iService); + } + } + + return lp_numservices(); +} + /*************************************************************************** Load the services array from the services file. Return True on success, False on failure. @@ -4339,8 +4995,9 @@ int lp_servicenumber(const char *pszServiceName) int iService; fstring serviceName; - if (!pszServiceName) + if (!pszServiceName) { return GLOBAL_SECTION_SNUM; + } for (iService = iNumServices - 1; iService >= 0; iService--) { if (VALID(iService) && ServicePtrs[iService]->szService) { @@ -4350,8 +5007,30 @@ int lp_servicenumber(const char *pszServiceName) */ fstrcpy(serviceName, ServicePtrs[iService]->szService); standard_sub_basic(get_current_username(), serviceName,sizeof(serviceName)); - if (strequal(serviceName, pszServiceName)) + if (strequal(serviceName, pszServiceName)) { break; + } + } + } + + if (iService >= 0 && ServicePtrs[iService]->usershare == USERSHARE_VALID) { + time_t last_mod; + + if (!usershare_exists(iService, &last_mod)) { + /* Remove the share security tdb entry for it. */ + delete_share_security(iService); + /* Remove it from the array. */ + free_service_byindex(iService); + /* Doesn't exist anymore. */ + return GLOBAL_SECTION_SNUM; + } + + /* Has it been modified ? If so delete and reload. */ + if (ServicePtrs[iService]->usershare_last_mod < last_mod) { + /* Remove it from the array. */ + free_service_byindex(iService); + /* and now reload it. */ + iService = load_usershare_service(pszServiceName); } } diff --git a/source/param/params.c b/source/param/params.c index 2a6c8b3e650..f5ce6bdb647 100644 --- a/source/param/params.c +++ b/source/param/params.c @@ -532,7 +532,7 @@ static myFILE *OpenConfFile( const char *FileName ) if (!ret) return NULL; - ret->buf = file_load(FileName, &ret->size); + ret->buf = file_load(FileName, &ret->size, 0); if( NULL == ret->buf ) { DEBUG( lvl, ("%s Unable to open configuration file \"%s\":\n\t%s\n", func, FileName, strerror(errno)) ); diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c index 4640eb6ae58..6266aa9cab7 100644 --- a/source/passdb/lookup_sid.c +++ b/source/passdb/lookup_sid.c @@ -3,6 +3,7 @@ uid/user handling Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Gerald (Jerry) Carter 2003 + Copyright (C) Volker Lendecke 2005 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 @@ -67,7 +68,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, if (strequal(domain, get_global_sam_name())) { /* It's our own domain, lookup the name in passdb */ - if (lookup_global_sam_name(name, &rid, &type)) { + if (lookup_global_sam_name(name, flags, &rid, &type)) { sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, rid); goto ok; @@ -87,16 +88,31 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, goto failed; } - if (domain[0] != '\0') { - /* An explicit domain name was given, here our last resort is - * winbind. */ - if (winbind_lookup_name(domain, name, &sid, &type)) { + /* Try the explicit winbind lookup first, don't let it guess the + * domain yet at this point yet. This comes later. */ + + if ((domain[0] != '\0') && + (winbind_lookup_name(domain, name, &sid, &type))) { + goto ok; + } + + if (strequal(domain, unix_users_domain_name())) { + if (lookup_unix_user_name(name, &sid)) { + type = SID_NAME_USER; + goto ok; + } + goto failed; + } + + if (strequal(domain, unix_groups_domain_name())) { + if (lookup_unix_group_name(name, &sid)) { + type = SID_NAME_DOM_GRP; goto ok; } goto failed; } - if (!(flags & LOOKUP_NAME_ISOLATED)) { + if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) { goto failed; } @@ -176,7 +192,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, /* Both cases are done by looking at our passdb */ - if (lookup_global_sam_name(name, &rid, &type)) { + if (lookup_global_sam_name(name, flags, &rid, &type)) { domain = talloc_strdup(tmp_ctx, get_global_sam_name()); sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, rid); @@ -232,6 +248,22 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, } /* 10. Don't translate */ + + /* 11. Ok, windows would end here. Samba has two more options: + Unmapped users and unmapped groups */ + + if (lookup_unix_user_name(name, &sid)) { + domain = talloc_strdup(tmp_ctx, unix_users_domain_name()); + type = SID_NAME_USER; + goto ok; + } + + if (lookup_unix_group_name(name, &sid)) { + domain = talloc_strdup(tmp_ctx, unix_groups_domain_name()); + type = SID_NAME_DOM_GRP; + goto ok; + } + failed: talloc_free(tmp_ctx); return False; @@ -265,113 +297,513 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx, return True; } -/***************************************************************** - *THE CANONICAL* convert SID to name function. - Tries local lookup first - for local sids, then tries winbind. -*****************************************************************/ +static BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + int num_rids, uint32 *rids, + const char **domain_name, + const char **names, uint32 *types) +{ + /* Unless the winbind interface is upgraded, fall back to ask for + * individual sids. I imagine introducing a lookuprids operation that + * directly proxies to lsa_lookupsids to the correct DC. -- vl */ + + int i; + for (i=0; inum_auths != 4) { + /* This can't be a domain */ + return False; } - if (sid_check_is_in_builtin(sid)) { - uint32 rid; + if (IS_DC) { + uint32 i, num_domains; + struct trustdom_info **domains; - SMB_ASSERT(sid_peek_rid(sid, &rid)); + /* This is relatively expensive, but it happens only on DCs + * and for SIDs that have 4 sub-authorities and thus look like + * domains */ - if (!lookup_builtin_rid(tmp_ctx, rid, &name)) { - goto failed; + if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx, + &num_domains, + &domains))) { + return False; } - /* There's only aliases in S-1-5-32 */ - type = SID_NAME_ALIAS; - domain = talloc_strdup(tmp_ctx, builtin_domain_name()); + for (i=0; isid)) { + *name = talloc_strdup(mem_ctx, + domains[i]->name); + return True; + } + } + return False; + } - goto ok; + if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) && + (type == SID_NAME_DOMAIN)) { + *name = tmp; + return True; } - if (winbind_lookup_sid(tmp_ctx, sid, &domain, &name, &type)) { - goto ok; + return False; +} + +/* + * This tries to implement the rather weird rules for the lsa_lookup level + * parameter. + * + * This is as close as we can get to what W2k3 does. With this we survive the + * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more + * different, but I assume that's just being too liberal. For example, W2k3 + * replies to everything else but the levels 1-6 with INVALID_PARAMETER + * whereas NT4 does the same as level 1 (I think). I did not fully test that + * with NT4, this is what w2k3 does. + * + * Level 1: Ask everywhere + * Level 2: Ask domain and trusted domains, no builtin and wkn + * Level 3: Only ask domain + * Level 4: W2k3ad: Only ask AD trusts + * Level 5: Don't lookup anything + * Level 6: Like 4 + */ + +static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level) +{ + int ret = False; + + switch(level) { + case 1: + ret = True; + break; + case 2: + ret = (!sid_check_is_builtin(sid) && + !sid_check_is_wellknown_domain(sid, NULL)); + break; + case 3: + case 4: + case 6: + ret = sid_check_is_domain(sid); + break; + case 5: + ret = False; + break; } - DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying " - "special SIDs.\n", sid_string_static(sid))); + DEBUG(10, ("%s SID %s in level %d\n", + ret ? "Accepting" : "Rejecting", + sid_string_static(sid), level)); + return ret; +} - if (lookup_wellknown_sid(tmp_ctx, sid, &domain, &name)) { - type = SID_NAME_WKN_GRP; - goto ok; +/* + * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with + * references to domains, it is explicitly made for this. + * + * This attempts to be as efficient as possible: It collects all SIDs + * belonging to a domain and hands them in bulk to the appropriate lookup + * function. In particular pdb_lookup_rids with ldapsam_trusted benefits + * *hugely* from this. Winbind is going to be extended with a lookup_rids + * interface as well, so on a DC we can do a bulk lsa_lookuprids to the + * appropriate DC. + */ + +NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, + const DOM_SID **sids, int level, + struct lsa_dom_info **ret_domains, + struct lsa_name_info **ret_names) +{ + TALLOC_CTX *tmp_ctx; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_name_info *name_infos; + struct lsa_dom_info *dom_infos; + + int i, j; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - failed: - DEBUG(10, ("Failed to lookup sid %s\n", sid_string_static(sid))); + name_infos = TALLOC_ARRAY(tmp_ctx, struct lsa_name_info, num_sids); + dom_infos = TALLOC_ZERO_ARRAY(tmp_ctx, struct lsa_dom_info, + MAX_REF_DOMAINS); + if ((name_infos == NULL) || (dom_infos == NULL)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + /* First build up the data structures: + * + * dom_infos is a list of domains referenced in the list of + * SIDs. Later we will walk the list of domains and look up the RIDs + * in bulk. + * + * name_infos is a shadow-copy of the SIDs array to collect the real + * data. + * + * dom_info->idxs is an index into the name_infos array. The + * difficulty we have here is that we need to keep the SIDs the client + * asked for in the same order for the reply + */ + + for (i=0; ivalid) { + /* No domains left, we're done */ + break; + } + + rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs); + + if (rids == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (j=0; jnum_idxs; j++) { + rids[j] = name_infos[dom->idxs[j]].rid; + } + + if (!lookup_rids(tmp_ctx, &dom->sid, + dom->num_idxs, rids, &dom->name, + &names, &types)) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + talloc_steal(dom_infos, dom->name); + + for (j=0; jnum_idxs; j++) { + int idx = dom->idxs[j]; + name_infos[idx].type = types[j]; + if (types[j] != SID_NAME_UNKNOWN) { + name_infos[idx].name = + talloc_steal(name_infos, names[j]); + } else { + name_infos[idx].name = NULL; + } + } + } + + *ret_domains = talloc_steal(mem_ctx, dom_infos); + *ret_names = talloc_steal(mem_ctx, name_infos); + result = NT_STATUS_OK; + + done: talloc_free(tmp_ctx); - return False; + return result; +} - ok: +/***************************************************************** + *THE CANONICAL* convert SID to name function. +*****************************************************************/ - if ((domain == NULL) || (name == NULL)) { - DEBUG(0, ("talloc failed\n")); - talloc_free(tmp_ctx); +BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, + const char **ret_domain, const char **ret_name, + enum SID_NAME_USE *ret_type) +{ + struct lsa_dom_info *domain; + struct lsa_name_info *name; + TALLOC_CTX *tmp_ctx; + BOOL ret = False; + + tmp_ctx = talloc_new(mem_ctx); + + if (tmp_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); return False; } + if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1, + &domain, &name))) { + goto done; + } + + if (name->type == SID_NAME_UNKNOWN) { + goto done; + } + if (ret_domain != NULL) { - *ret_domain = talloc_steal(mem_ctx, domain); + *ret_domain = talloc_steal(mem_ctx, domain->name); } if (ret_name != NULL) { - *ret_name = talloc_steal(mem_ctx, name); + *ret_name = talloc_steal(mem_ctx, name->name); } if (ret_type != NULL) { - *ret_type = type; + *ret_type = name->type; } + ret = True; + + done: + if (ret) { + DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", + sid_string_static(sid), domain->name, + name->name, name->type)); + } else { + DEBUG(10, ("failed to lookup sid %s\n", + sid_string_static(sid))); + } talloc_free(tmp_ctx); - return True; + return ret; } /***************************************************************** @@ -448,7 +880,7 @@ static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) Store uid to SID mapping in cache. *****************************************************************/ -static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) +void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) { struct uid_sid_cache *pc; @@ -520,7 +952,7 @@ static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) Store gid to SID mapping in cache. *****************************************************************/ -static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) +void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) { struct gid_sid_cache *pc; @@ -552,200 +984,255 @@ static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) *THE CANONICAL* convert uid_t to SID function. *****************************************************************/ -NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid) +void uid_to_sid(DOM_SID *psid, uid_t uid) { uid_t low, high; + uint32 rid; ZERO_STRUCTP(psid); if (fetch_sid_from_uid_cache(psid, uid)) - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + return; - /* DC's never use winbindd to resolve users outside the - defined idmap range */ + if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) && + winbind_uid_to_sid(psid, uid)) { - if ( lp_server_role()==ROLE_DOMAIN_MEMBER - || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) ) - { - if (winbind_uid_to_sid(psid, uid)) { - - DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", - (unsigned int)uid, sid_string_static(psid))); + DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", + (unsigned int)uid, sid_string_static(psid))); + goto done; + } - if (psid) - store_uid_sid_cache(psid, uid); - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); - } + if (pdb_uid_to_rid(uid, &rid)) { + /* This is a mapped user */ + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, rid); + goto done; } - if (!local_uid_to_sid(psid, uid)) { - DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid )); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_rid_algorithm() && (uid < max_algorithmic_uid())) { + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, algorithmic_pdb_uid_to_user_rid(uid)); + goto done; + } else { + sid_copy(psid, &global_sid_Unix_Users); + sid_append_rid(psid, uid); + goto done; } - + + done: DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_string_static(psid))); store_uid_sid_cache(psid, uid); - return NT_STATUS_OK; + return; } /***************************************************************** *THE CANONICAL* convert gid_t to SID function. *****************************************************************/ -NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid) +void gid_to_sid(DOM_SID *psid, gid_t gid) { gid_t low, high; ZERO_STRUCTP(psid); if (fetch_sid_from_gid_cache(psid, gid)) - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + return; - /* DC's never use winbindd to resolve groups outside the - defined idmap range */ + if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) && + winbind_gid_to_sid(psid, gid)) { - if ( lp_server_role()==ROLE_DOMAIN_MEMBER - || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) ) - { - if (winbind_gid_to_sid(psid, gid)) { + DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", + (unsigned int)gid, sid_string_static(psid))); + goto done; + } - DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", - (unsigned int)gid, sid_string_static(psid))); - - if (psid) - store_gid_sid_cache(psid, gid); - return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); - } + if (pdb_gid_to_sid(gid, psid)) { + /* This is a mapped group */ + goto done; } - if (!local_gid_to_sid(psid, gid)) { - DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid )); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_rid_algorithm() && (gid < max_algorithmic_gid())) { + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, pdb_gid_to_group_rid(gid)); + goto done; + } else { + sid_copy(psid, &global_sid_Unix_Groups); + sid_append_rid(psid, gid); + goto done; } - + + done: DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_string_static(psid))); store_gid_sid_cache(psid, gid); - return NT_STATUS_OK; + return; } /***************************************************************** *THE CANONICAL* convert SID to uid function. *****************************************************************/ -NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid) +BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid) { - enum SID_NAME_USE name_type; + enum SID_NAME_USE type; + uint32 rid; + gid_t gid; if (fetch_uid_from_cache(puid, psid)) - return NT_STATUS_OK; + return True; - /* if this is our SID then go straight to a local lookup */ - - if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) { - DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n", - sid_string_static(psid) )); - - if ( local_sid_to_uid(puid, psid, &name_type) ) - goto success; - - DEBUG(10,("sid_to_uid: local lookup failed\n")); - - return NT_STATUS_UNSUCCESSFUL; + if (fetch_gid_from_cache(&gid, psid)) { + return False; } - - /* If it is not our local domain, only hope is winbindd */ - if ( !winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type) ) { - DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n", - sid_string_static(psid) )); - - return NT_STATUS_UNSUCCESSFUL; + if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) { + uid_t uid = rid; + *puid = uid; + goto done; } - /* If winbindd does know the SID, ensure this is a user */ + if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + union unid_t id; + + if (pdb_sid_to_id(psid, &id, &type)) { + if (type != SID_NAME_USER) { + DEBUG(5, ("sid %s is a %s, expected a user\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } + *puid = id.uid; + goto done; + } + if (pdb_rid_algorithm() && + algorithmic_pdb_rid_is_user(rid)) { + *puid = algorithmic_pdb_user_rid_to_uid(rid); + goto done; + } - if (name_type != SID_NAME_USER) { - DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n", - (unsigned int)name_type )); - return NT_STATUS_INVALID_PARAMETER; + /* This was ours, but it was neither mapped nor + * algorithmic. Fail */ + return False; } - /* get the uid. Has to work or else we are dead in the water */ + if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) { + + if (type != SID_NAME_USER) { + DEBUG(10, ("sid_to_uid: sid %s is a %s\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } - if ( !winbind_sid_to_uid(puid, psid) ) { - DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n", - sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + if (!winbind_sid_to_uid(puid, psid)) { + DEBUG(5, ("sid_to_uid: winbind failed to allocate a " + "new uid for sid %s\n", + sid_string_static(psid))); + return False; + } + goto done; } -success: + /* TODO: Here would be the place to allocate both a gid and a uid for + * the SID in question */ + + return False; + + done: DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid), (unsigned int)*puid )); store_uid_sid_cache(psid, *puid); - - return NT_STATUS_OK; + return True; } + /***************************************************************** *THE CANONICAL* convert SID to gid function. Group mapping is used for gids that maps to Wellknown SIDs *****************************************************************/ -NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid) +BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid) { - enum SID_NAME_USE name_type; + uint32 rid; + GROUP_MAP map; + union unid_t id; + enum SID_NAME_USE type; + uid_t uid; if (fetch_gid_from_cache(pgid, psid)) - return NT_STATUS_OK; + return True; - /* - * First we must look up the name and decide if this is a group sid. - * Group mapping can deal with foreign SIDs - */ + if (fetch_uid_from_cache(&uid, psid)) + return False; + + if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) { + gid_t gid = rid; + *pgid = gid; + goto done; + } + + if (sid_check_is_in_builtin(psid) && pdb_getgrsid(&map, *psid)) { + *pgid = map.gid; + goto done; + } - if ( local_sid_to_gid(pgid, psid, &name_type) ) - goto success; + if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + if (pdb_sid_to_id(psid, &id, &type)) { + if ((type != SID_NAME_DOM_GRP) && + (type != SID_NAME_ALIAS)) { + DEBUG(5, ("sid %s is a %s, expected a group\n", + sid_string_static(psid), + sid_type_lookup(type))); + return False; + } + *pgid = id.gid; + goto done; + } + if (pdb_rid_algorithm() && + !algorithmic_pdb_rid_is_user(rid)) { + /* This must be a group, presented as alias */ + *pgid = pdb_group_rid_to_gid(rid); + goto done; + } + /* This was ours, but it was neither mapped nor + * algorithmic. Fail. */ + return False; + } - if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type)) { - DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then " - "winbind)\n", sid_string_static(psid))); + if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) { + DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, " + "then winbind)\n", sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + return False; } /* winbindd knows it; Ensure this is a group sid */ - if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) - && (name_type != SID_NAME_WKN_GRP)) - { - DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n", - (unsigned int)name_type )); - - /* winbindd is running and knows about this SID. Just the wrong type. - Don't fallback to a local lookup here */ - - return NT_STATUS_INVALID_PARAMETER; + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is " + "a %s\n", sid_type_lookup(type))); + return False; } /* winbindd knows it and it is a type of group; sid_to_gid must succeed or we are dead in the water */ if ( !winbind_sid_to_gid(pgid, psid) ) { - DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n", - sid_string_static(psid))); - return NT_STATUS_UNSUCCESSFUL; + DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid " + "for sid %s\n", sid_string_static(psid))); + return False; } -success: + done: DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid), (unsigned int)*pgid )); store_gid_sid_cache(psid, *pgid); - return NT_STATUS_OK; + return True; } diff --git a/source/passdb/machine_sid.c b/source/passdb/machine_sid.c index 074a516bcb6..d7cae06749c 100644 --- a/source/passdb/machine_sid.c +++ b/source/passdb/machine_sid.c @@ -35,13 +35,14 @@ static DOM_SID *global_sam_sid=NULL; Read a SID from a file. This is for compatibility with the old MACHINE.SID style of SID storage ****************************************************************************/ + static BOOL read_sid_from_file(const char *fname, DOM_SID *sid) { char **lines; int numlines; BOOL ret; - lines = file_lines_load(fname, &numlines); + lines = file_lines_load(fname, &numlines,0); if (!lines || numlines < 1) { if (lines) file_lines_free(lines); diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index f9f6021d81b..90a51d1cbdc 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -350,34 +350,129 @@ NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd) on the UNIX user. Pass in a RID if you have one ************************************************************/ -NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username, - uint32 rid) +NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username) { - NTSTATUS nt_status = NT_STATUS_NO_MEMORY; + NTSTATUS result; struct passwd *pwd; - BOOL ret; - - pwd = Get_Pwnam(username); + uint32 user_rid; + DOM_SID user_sid, group_sid; + TALLOC_CTX *mem_ctx; + enum SID_NAME_USE type; - if (!pwd) - return NT_STATUS_NO_SUCH_USER; - - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { - *new_sam_acct = NULL; - return nt_status; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - /* see if we need to generate a new rid using the 2.2 algorithm */ - if ( rid == 0 && lp_enable_rid_algorithm() ) { - DEBUG(10,("pdb_init_sam_new: no RID specified. Generating one via old algorithm\n")); - rid = algorithmic_pdb_uid_to_user_rid(pwd->pw_uid); + pwd = Get_Pwnam_alloc(mem_ctx, username); + + if (pwd == NULL) { + DEBUG(10, ("Could not find user %s\n", username)); + result = NT_STATUS_NO_SUCH_USER; + goto done; } - - /* set the new SID */ - - ret = pdb_set_user_sid_from_rid( *new_sam_acct, rid, PDB_SET ); - - return (ret ? NT_STATUS_OK : NT_STATUS_NO_SUCH_USER); + + result = pdb_init_sam_pw(new_sam_acct, pwd); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_init_sam_pw failed: %s\n", nt_errstr(result))); + goto done; + } + + if (pdb_rid_algorithm()) { + if (!pdb_set_user_sid_from_rid( + *new_sam_acct, + algorithmic_pdb_uid_to_user_rid(pwd->pw_uid), + PDB_SET)) { + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + if (!pdb_set_group_sid_from_rid( + *new_sam_acct, pdb_gid_to_group_rid(pwd->pw_gid), + PDB_SET)) { + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + result = NT_STATUS_OK; + goto done; + } + + /* No algorithmic mapping, meaning that we have to figure out the + * primary group SID according to group mapping and the user SID must + * be a newly allocated one */ + + if (!pdb_gid_to_sid(pwd->pw_gid, &group_sid)) { + struct group *grp; + GROUP_MAP map; + + grp = getgrgid(pwd->pw_gid); + if (grp == NULL) { + DEBUG(1, ("Primary group %d of user %s does not " + "exist.\n", pwd->pw_gid, username)); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + DEBUG(5, ("Primary group %s of user %s is not mapped to " + "a domain group, auto-mapping it\n", + grp->gr_name, username)); + result = map_unix_group(grp, &map); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(1, ("Failed to map group %s\n", grp->gr_name)); + goto done; + } + sid_copy(&group_sid, &map.sid); + DEBUG(5, ("Mapped unix group %s to SID %s\n", + grp->gr_name, sid_string_static(&group_sid))); + } + + /* Now check that it's actually a domain group and not something + * else */ + + if (!lookup_sid(mem_ctx, &group_sid, NULL, NULL, &type)) { + DEBUG(3, ("Could not lookup %s's primary group sid %s\n", + username, sid_string_static(&group_sid))); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + if (type != SID_NAME_DOM_GRP) { + DEBUG(3, ("Primary group for user %s is a %s and not a domain " + "group\n", username, sid_type_lookup(type))); + result = NT_STATUS_INVALID_PRIMARY_GROUP; + goto done; + } + + if (!pdb_set_group_sid(*new_sam_acct, &group_sid, PDB_SET)) { + DEBUG(3, ("Could not set group SID\n")); + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + if (!pdb_new_rid(&user_rid)) { + DEBUG(3, ("Could not allocate a new RID\n")); + result = NT_STATUS_ACCESS_DENIED; + goto done; + } + + sid_copy(&user_sid, get_global_sam_sid()); + sid_append_rid(&user_sid, user_rid); + + if (!pdb_set_user_sid(*new_sam_acct, &user_sid, PDB_SET)) { + DEBUG(3, ("pdb_set_user_sid failed\n")); + result = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = NT_STATUS_OK; + + done: + if (!NT_STATUS_IS_OK(result) && (*new_sam_acct != NULL)) { + pdb_free_sam(new_sam_acct); + } + + talloc_free(mem_ctx); + return result; } @@ -666,6 +761,11 @@ uid_t algorithmic_pdb_user_rid_to_uid(uint32 user_rid) return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER); } +uid_t max_algorithmic_uid(void) +{ + return algorithmic_pdb_user_rid_to_uid(0xfffffffe); +} + /******************************************************************* converts UNIX uid to an NT User RID. ********************************************************************/ @@ -686,6 +786,11 @@ gid_t pdb_group_rid_to_gid(uint32 group_rid) return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER); } +gid_t max_algorithmic_gid(void) +{ + return pdb_group_rid_to_gid(0xffffffff); +} + /******************************************************************* converts NT Group RID to a UNIX uid. @@ -731,130 +836,12 @@ BOOL algorithmic_pdb_rid_is_user(uint32 rid) return False; } -/******************************************************************* - Look up a rid in the SAM we're responsible for (i.e. passdb) - ********************************************************************/ - -BOOL lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid, const char **name, - enum SID_NAME_USE *psid_name_use) -{ - SAM_ACCOUNT *sam_account = NULL; - GROUP_MAP map; - BOOL ret; - DOM_SID sid; - - *psid_name_use = SID_NAME_UNKNOWN; - - DEBUG(5,("lookup_global_sam_rid: looking up RID %u.\n", - (unsigned int)rid)); - - sid_copy(&sid, get_global_sam_sid()); - sid_append_rid(&sid, rid); - - /* see if the passdb can help us with the name of the user */ - if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) { - return False; - } - - /* BEING ROOT BLLOCK */ - become_root(); - if (pdb_getsampwsid(sam_account, &sid)) { - unbecome_root(); /* -----> EXIT BECOME_ROOT() */ - *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account)); - *psid_name_use = SID_NAME_USER; - - pdb_free_sam(&sam_account); - - return True; - } - pdb_free_sam(&sam_account); - - ret = pdb_getgrsid(&map, sid); - unbecome_root(); - /* END BECOME_ROOT BLOCK */ - - if ( ret ) { - if (map.gid!=(gid_t)-1) { - DEBUG(5,("lookup_global_sam_rid: mapped group %s to " - "gid %u\n", map.nt_name, - (unsigned int)map.gid)); - } else { - DEBUG(5,("lookup_global_sam_rid: mapped group %s to " - "no unix gid. Returning name.\n", - map.nt_name)); - } - - *name = talloc_strdup(mem_ctx, map.nt_name); - *psid_name_use = map.sid_name_use; - return True; - } - - if (rid == DOMAIN_USER_RID_ADMIN) { - *psid_name_use = SID_NAME_USER; - *name = talloc_strdup(mem_ctx, "Administrator"); - return True; - } - - if (algorithmic_pdb_rid_is_user(rid)) { - uid_t uid; - struct passwd *pw = NULL; - - DEBUG(5, ("assuming RID %u is a user\n", (unsigned)rid)); - - uid = algorithmic_pdb_user_rid_to_uid(rid); - pw = sys_getpwuid( uid ); - - DEBUG(5,("lookup_global_sam_rid: looking up uid %u %s\n", - (unsigned int)uid, pw ? "succeeded" : "failed" )); - - if ( !pw ) { - *name = talloc_asprintf(mem_ctx, "unix_user.%u", - (unsigned int)uid); - } else { - *name = talloc_strdup(mem_ctx, pw->pw_name ); - } - - DEBUG(5,("lookup_global_sam_rid: found user %s for rid %u\n", - *name, (unsigned int)rid )); - - *psid_name_use = SID_NAME_USER; - - return ( pw != NULL ); - } else { - gid_t gid; - struct group *gr; - - DEBUG(5, ("assuming RID %u is a group\n", (unsigned)rid)); - - gid = pdb_group_rid_to_gid(rid); - gr = getgrgid(gid); - - DEBUG(5,("lookup_global_sam_rid: looking up gid %u %s\n", - (unsigned int)gid, gr ? "succeeded" : "failed" )); - - if( !gr ) { - *name = talloc_asprintf(mem_ctx, "unix_group.%u", - (unsigned int)gid); - } else { - *name = talloc_strdup(mem_ctx, gr->gr_name); - } - - DEBUG(5,("lookup_global_sam_rid: found group %s for rid %u\n", - *name, (unsigned int)rid )); - - /* assume algorithmic groups are domain global groups */ - - *psid_name_use = SID_NAME_DOM_GRP; - - return ( gr != NULL ); - } -} - /******************************************************************* Convert a name into a SID. Used in the lookup name rpc. ********************************************************************/ -BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE *type) +BOOL lookup_global_sam_name(const char *c_user, int flags, uint32_t *rid, + enum SID_NAME_USE *type) { fstring user; SAM_ACCOUNT *sam_account = NULL; @@ -877,7 +864,13 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE /* BEGIN ROOT BLOCK */ become_root(); - if (pdb_getsampwnam(sam_account, user)) { + + /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work + * correctly in the case where foo also exists as a user. If the flag + * is set, don't look for users at all. */ + + if (((flags & LOOKUP_NAME_GROUP) == 0) && + pdb_getsampwnam(sam_account, user)) { const DOM_SID *user_sid; unbecome_root(); @@ -891,15 +884,7 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE } sid_peek_rid(user_sid, rid); - - if (pdb_get_acct_ctrl(sam_account) & - (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST)) { - /* We have to filter them out in lsa_lookupnames, - * indicate that this is not a real user. */ - *type = SID_NAME_COMPUTER; - } else { - *type = SID_NAME_USER; - } + *type = SID_NAME_USER; pdb_free_sam(&sam_account); return True; } @@ -929,6 +914,8 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE return True; } + return False; + /* it's not a mapped group */ grp = getgrnam(user); if(!grp) { @@ -965,13 +952,14 @@ BOOL lookup_global_sam_name(const char *c_user, uint32_t *rid, enum SID_NAME_USE Change a password entry in the local smbpasswd file. *************************************************************/ -BOOL local_password_change(const char *user_name, int local_flags, +NTSTATUS local_password_change(const char *user_name, int local_flags, const char *new_passwd, char *err_str, size_t err_str_len, char *msg_str, size_t msg_str_len) { SAM_ACCOUNT *sam_pass=NULL; uint16 other_acb; + NTSTATUS result; *err_str = '\0'; *msg_str = '\0'; @@ -985,14 +973,30 @@ BOOL local_password_change(const char *user_name, int local_flags, pdb_free_sam(&sam_pass); if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) { - /* Might not exist in /etc/passwd. Use rid algorithm here */ - if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name, 0))) { - slprintf(err_str, err_str_len-1, "Failed to initialise SAM_ACCOUNT for user %s. Does this user exist in the UNIX password database ?\n", user_name); - return False; + int tmp_debug = DEBUGLEVEL; + + /* Might not exist in /etc/passwd. */ + + if (tmp_debug < 1) { + DEBUGLEVEL = 1; + } + + result = pdb_init_sam_new(&sam_pass, user_name); + DEBUGLEVEL = tmp_debug; + if (NT_STATUS_EQUAL(result, + NT_STATUS_INVALID_PRIMARY_GROUP)) { + return result; + } + + if (!NT_STATUS_IS_OK(result)) { + slprintf(err_str, err_str_len-1, "Failed to " + "initialize account for user %s: %s\n", + user_name, nt_errstr(result)); + return result; } } else { slprintf(err_str, err_str_len-1,"Failed to find entry for user %s.\n", user_name); - return False; + return NT_STATUS_NO_SUCH_USER; } } else { unbecome_root(); @@ -1006,19 +1010,19 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST | other_acb, PDB_CHANGED) ) { slprintf(err_str, err_str_len - 1, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST | other_acb, PDB_CHANGED)) { slprintf(err_str, err_str_len - 1, "Failed to set 'domain trust account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else { if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL | other_acb, PDB_CHANGED)) { slprintf(err_str, err_str_len - 1, "Failed to set 'normal account' flags for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1031,13 +1035,13 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED, PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to set 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_ENABLE_USER) { if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1045,7 +1049,7 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ, PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to set 'no password required' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_SET_PASSWORD) { /* @@ -1061,19 +1065,19 @@ BOOL local_password_change(const char *user_name, int local_flags, if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ), PDB_CHANGED)) { slprintf(err_str, err_str_len-1, "Failed to unset 'no password required' flag for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) { slprintf(err_str, err_str_len-1, "Failed to set password for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } @@ -1081,24 +1085,25 @@ BOOL local_password_change(const char *user_name, int local_flags, if (pdb_add_sam_account(sam_pass)) { slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name); pdb_free_sam(&sam_pass); - return True; + return NT_STATUS_OK; } else { slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_DELETE_USER) { if (!pdb_delete_sam_account(sam_pass)) { slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return NT_STATUS_UNSUCCESSFUL; } slprintf(msg_str, msg_str_len-1, "Deleted user %s.\n", user_name); } else { - if(!pdb_update_sam_account(sam_pass)) { + result = pdb_update_sam_account(sam_pass); + if(!NT_STATUS_IS_OK(result)) { slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); - return False; + return result; } if(local_flags & LOCAL_DISABLE_USER) slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name); @@ -1109,232 +1114,7 @@ BOOL local_password_change(const char *user_name, int local_flags, } pdb_free_sam(&sam_pass); - return True; -} - -/**************************************************************************** - Convert a uid to SID - algorithmic. -****************************************************************************/ - -DOM_SID *algorithmic_uid_to_sid(DOM_SID *psid, uid_t uid) -{ - if ( !lp_enable_rid_algorithm() ) - return NULL; - - DEBUG(8,("algorithmic_uid_to_sid: falling back to RID algorithm\n")); - sid_copy( psid, get_global_sam_sid() ); - sid_append_rid( psid, algorithmic_pdb_uid_to_user_rid(uid) ); - DEBUG(10,("algorithmic_uid_to_sid: uid (%d) -> SID %s.\n", - (unsigned int)uid, sid_string_static(psid) )); - - return psid; -} - -/**************************************************************************** - Convert a uid to SID - locally. -****************************************************************************/ - -DOM_SID *local_uid_to_sid(DOM_SID *psid, uid_t uid) -{ - SAM_ACCOUNT *sampw = NULL; - struct passwd *unix_pw; - BOOL ret; - - unix_pw = sys_getpwuid( uid ); - - if ( !unix_pw ) { - DEBUG(4,("local_uid_to_sid: host has no idea of uid %lu\n", (unsigned long)uid)); - return algorithmic_uid_to_sid( psid, uid); - } - - if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { - DEBUG(0,("local_uid_to_sid: failed to allocate SAM_ACCOUNT object\n")); - return NULL; - } - - become_root(); - ret = pdb_getsampwnam( sampw, unix_pw->pw_name ); - unbecome_root(); - - if ( ret ) - sid_copy( psid, pdb_get_user_sid(sampw) ); - else { - DEBUG(4,("local_uid_to_sid: User %s [uid == %lu] has no samba account\n", - unix_pw->pw_name, (unsigned long)uid)); - - algorithmic_uid_to_sid( psid, uid); - } - - pdb_free_sam(&sampw); - - DEBUG(10,("local_uid_to_sid: uid (%d) -> SID %s (%s).\n", - (unsigned int)uid, sid_string_static(psid), unix_pw->pw_name)); - - return psid; -} - -/**************************************************************************** - Convert a SID to uid - locally. -****************************************************************************/ - -BOOL local_sid_to_uid(uid_t *puid, const DOM_SID *psid, enum SID_NAME_USE *name_type) -{ - SAM_ACCOUNT *sampw = NULL; - struct passwd *unix_pw; - const char *user_name; - - *name_type = SID_NAME_UNKNOWN; - - /* - * We can only convert to a uid if this is our local - * Domain SID (ie. we are the controling authority). - */ - if (!sid_check_is_in_our_domain(psid) ) { - DEBUG(5,("local_sid_to_uid: this SID (%s) is not from our domain\n", sid_string_static(psid))); - return False; - } - - /* lookup the user account */ - - if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { - DEBUG(0,("local_sid_to_uid: Failed to allocate memory for SAM_ACCOUNT object\n")); - return False; - } - - become_root(); - if ( !pdb_getsampwsid(sampw, psid) ) { - unbecome_root(); - pdb_free_sam(&sampw); - DEBUG(8,("local_sid_to_uid: Could not find SID %s in passdb\n", - sid_string_static(psid))); - return False; - } - unbecome_root(); - - user_name = pdb_get_username(sampw); - - unix_pw = sys_getpwnam( user_name ); - - if ( !unix_pw ) { - DEBUG(0,("local_sid_to_uid: %s found in passdb but getpwnam() return NULL!\n", - user_name)); - pdb_free_sam( &sampw ); - return False; - } - - *puid = unix_pw->pw_uid; - - DEBUG(10,("local_sid_to_uid: SID %s -> uid (%u) (%s).\n", sid_string_static(psid), - (unsigned int)*puid, user_name )); - - *name_type = SID_NAME_USER; - pdb_free_sam( &sampw ); - return True; -} - -/**************************************************************************** - Convert a gid to SID - locally. -****************************************************************************/ - -DOM_SID *local_gid_to_sid(DOM_SID *psid, gid_t gid) -{ - GROUP_MAP group; - BOOL ret; - - /* we don't need to disable winbindd since the gid is stored in - the GROUP_MAP object */ - - /* done as root since ldap backend requires root to open a connection */ - - become_root(); - ret = pdb_getgrgid( &group, gid ); - unbecome_root(); - - if ( !ret ) { - - /* fallback to rid mapping if enabled */ - - if ( lp_enable_rid_algorithm() ) { - sid_copy(psid, get_global_sam_sid()); - sid_append_rid(psid, pdb_gid_to_group_rid(gid)); - - DEBUG(10,("local_gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", - (unsigned int)gid, sid_string_static(psid))); - - return psid; - } - else - return NULL; - } - - sid_copy( psid, &group.sid ); - - DEBUG(10,("local_gid_to_sid: gid (%d) -> SID %s.\n", - (unsigned int)gid, sid_string_static(psid))); - - return psid; -} - -/**************************************************************************** - Convert a SID to gid - locally. -****************************************************************************/ - -BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_type) -{ - uint32 rid; - GROUP_MAP group; - BOOL ret; - - *name_type = SID_NAME_UNKNOWN; - - /* This call can enumerate group mappings for foreign sids as well. - So don't check for a match against our domain SID */ - - /* we don't need to disable winbindd since the gid is stored in - the GROUP_MAP object */ - - become_root(); - ret = pdb_getgrsid(&group, *psid); - unbecome_root(); - - if ( !ret ) { - - /* Fallback to algorithmic rid mapping if enabled */ - - if ( lp_enable_rid_algorithm() ) { - - if (!sid_check_is_in_our_domain(psid) ) { - DEBUG(5,("local_sid_to_gid: RID algorithm only supported for our domain (%s is not)\n", sid_string_static(psid))); - return False; - } - - if (!sid_peek_rid(psid, &rid)) { - DEBUG(10,("local_sid_to_gid: invalid SID!\n")); - return False; - } - - DEBUG(10,("local_sid_to_gid: Fall back to algorithmic mapping\n")); - - if (algorithmic_pdb_rid_is_user(rid)) { - DEBUG(3, ("local_sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(psid))); - return False; - } else { - *pgid = pdb_group_rid_to_gid(rid); - DEBUG(10,("local_sid_to_gid: mapping: %s -> %u\n", sid_string_static(psid), (unsigned int)(*pgid))); - return True; - } - } - - return False; - } - - *pgid = group.gid; - *name_type = group.sid_name_use; - - DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u)\n", sid_string_static(psid), - (unsigned int)*pgid)); - - return True; + return NT_STATUS_OK; } /********************************************************************** @@ -2251,51 +2031,6 @@ BOOL pdb_copy_sam_account(const SAM_ACCOUNT *src, SAM_ACCOUNT **dst) return result; } -/********************************************************************** -**********************************************************************/ - -static BOOL get_free_ugid_range(uint32 *low, uint32 *high) -{ - uid_t u_low, u_high; - gid_t g_low, g_high; - - if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) { - return False; - } - - *low = (u_low < g_low) ? u_low : g_low; - *high = (u_high < g_high) ? u_high : g_high; - - return True; -} - -/****************************************************************** - Get the the non-algorithmic RID range if idmap range are defined -******************************************************************/ - -BOOL get_free_rid_range(uint32 *low, uint32 *high) -{ - uint32 id_low, id_high; - - if (!lp_enable_rid_algorithm()) { - *low = BASE_RID; - *high = (uint32)-1; - } - - if (!get_free_ugid_range(&id_low, &id_high)) { - return False; - } - - *low = algorithmic_pdb_uid_to_user_rid(id_low); - if (algorithmic_pdb_user_rid_to_uid((uint32)-1) < id_high) { - *high = (uint32)-1; - } else { - *high = algorithmic_pdb_uid_to_user_rid(id_high); - } - - return True; -} - /********************************************************************* Update the bad password count checking the AP_RESET_COUNT_TIME *********************************************************************/ diff --git a/source/passdb/pdb_get_set.c b/source/passdb/pdb_get_set.c index 783e9e23fa3..71fb36e0d5e 100644 --- a/source/passdb/pdb_get_set.c +++ b/source/passdb/pdb_get_set.c @@ -958,7 +958,8 @@ BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[NT_HASH_LEN], enum data_blob_clear_free(&sampass->private_u.nt_pw); if (pwd) { - sampass->private_u.nt_pw = data_blob(pwd, NT_HASH_LEN); + sampass->private_u.nt_pw = + data_blob_talloc(sampass->mem_ctx, pwd, NT_HASH_LEN); } else { sampass->private_u.nt_pw = data_blob(NULL, 0); } @@ -978,7 +979,8 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN], data_blob_clear_free(&sampass->private_u.lm_pw); if (pwd) { - sampass->private_u.lm_pw = data_blob(pwd, LM_HASH_LEN); + sampass->private_u.lm_pw = + data_blob_talloc(sampass->mem_ctx, pwd, LM_HASH_LEN); } else { sampass->private_u.lm_pw = data_blob(NULL, 0); } @@ -1093,8 +1095,10 @@ BOOL pdb_set_backend_private_data (SAM_ACCOUNT *sampass, void *private_data, if (!sampass) return False; - if (sampass->private_u.backend_private_data && sampass->private_u.backend_private_data_free_fn) { - sampass->private_u.backend_private_data_free_fn(&sampass->private_u.backend_private_data); + if (sampass->private_u.backend_private_data && + sampass->private_u.backend_private_data_free_fn) { + sampass->private_u.backend_private_data_free_fn( + &sampass->private_u.backend_private_data); } sampass->private_u.backend_private_data = private_data; diff --git a/source/passdb/pdb_interface.c b/source/passdb/pdb_interface.c index 4808af39081..d8afff21115 100644 --- a/source/passdb/pdb_interface.c +++ b/source/passdb/pdb_interface.c @@ -36,7 +36,10 @@ static void lazy_initialize_passdb(void) } static struct pdb_init_function_entry *pdb_find_backend_entry(const char *name); - +static BOOL lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid, + const char **name, + enum SID_NAME_USE *psid_name_use, + union unid_t *unix_id); /******************************************************************* Clean up uninitialised passwords. The only way to tell that these values are not 'real' is that they do not @@ -526,9 +529,10 @@ static NTSTATUS context_enum_group_members(struct pdb_context *context, } static NTSTATUS context_enum_group_memberships(struct pdb_context *context, - const char *username, - gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; @@ -539,8 +543,8 @@ static NTSTATUS context_enum_group_memberships(struct pdb_context *context, } return context->pdb_methods-> - enum_group_memberships(context->pdb_methods, username, - primary_gid, pp_sids, pp_gids, p_num_groups); + enum_group_memberships(context->pdb_methods, mem_ctx, user, + pp_sids, pp_gids, p_num_groups); } static NTSTATUS context_find_alias(struct pdb_context *context, @@ -757,6 +761,63 @@ static NTSTATUS context_get_seq_num(struct pdb_context *context, time_t *seq_num return context->pdb_methods->get_seq_num(context->pdb_methods, seq_num); } + +static BOOL context_uid_to_rid(struct pdb_context *context, uid_t uid, + uint32 *rid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->uid_to_rid(context->pdb_methods, uid, + rid); +} + +static BOOL context_gid_to_sid(struct pdb_context *context, gid_t gid, + DOM_SID *sid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->gid_to_sid(context->pdb_methods, gid, + sid); +} + +static BOOL context_sid_to_id(struct pdb_context *context, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->sid_to_id(context->pdb_methods, sid, + id, type); +} + +static BOOL context_rid_algorithm(struct pdb_context *context) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->rid_algorithm(context->pdb_methods); +} + +static BOOL context_new_rid(struct pdb_context *context, uint32 *rid) +{ + if ((context == NULL) || (context->pdb_methods == NULL)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->new_rid(context->pdb_methods, rid); +} /****************************************************************** Free and cleanup a pdb context, any associated data and anything @@ -936,6 +997,13 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_search_groups = context_search_groups; (*context)->pdb_search_aliases = context_search_aliases; + (*context)->pdb_uid_to_rid = context_uid_to_rid; + (*context)->pdb_gid_to_sid = context_gid_to_sid; + (*context)->pdb_sid_to_id = context_sid_to_id; + + (*context)->pdb_rid_algorithm = context_rid_algorithm; + (*context)->pdb_new_rid = context_new_rid; + (*context)->free_fn = free_pdb_context; return NT_STATUS_OK; @@ -1126,12 +1194,12 @@ BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct) return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct)); } -BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) +NTSTATUS pdb_update_sam_account(SAM_ACCOUNT *sam_acct) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } if (sam_account_cache != NULL) { @@ -1139,7 +1207,7 @@ BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) sam_account_cache = NULL; } - return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct)); + return pdb_context->pdb_update_sam_account(pdb_context, sam_acct); } BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) @@ -1221,28 +1289,26 @@ BOOL pdb_getgrnam(GROUP_MAP *map, const char *name) pdb_getgrnam(pdb_context, map, name)); } -BOOL pdb_add_group_mapping_entry(GROUP_MAP *map) +NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_group_mapping_entry(pdb_context, map)); + return pdb_context->pdb_add_group_mapping_entry(pdb_context, map); } -BOOL pdb_update_group_mapping_entry(GROUP_MAP *map) +NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_update_group_mapping_entry(pdb_context, map)); + return pdb_context->pdb_update_group_mapping_entry(pdb_context, map); } BOOL pdb_delete_group_mapping_entry(DOM_SID sid) @@ -1286,7 +1352,7 @@ NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx, pp_member_rids, p_num_members); } -NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid, +NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *user, DOM_SID **pp_sids, gid_t **pp_gids, size_t *p_num_groups) { @@ -1296,9 +1362,9 @@ NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid, return NT_STATUS_UNSUCCESSFUL; } - return pdb_context->pdb_enum_group_memberships(pdb_context, username, - primary_gid, pp_sids, pp_gids, - p_num_groups); + return pdb_context->pdb_enum_group_memberships( + pdb_context, mem_ctx, user, + pp_sids, pp_gids, p_num_groups); } BOOL pdb_find_alias(const char *name, DOM_SID *sid) @@ -1361,60 +1427,58 @@ BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info) info)); } -BOOL pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) +NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_add_aliasmem(pdb_context, alias, member)); + return pdb_context->pdb_add_aliasmem(pdb_context, alias, member); } -BOOL pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) +NTSTATUS pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_del_aliasmem(pdb_context, alias, member)); + return pdb_context->pdb_del_aliasmem(pdb_context, alias, member); } -BOOL pdb_enum_aliasmem(const DOM_SID *alias, - DOM_SID **pp_members, size_t *p_num_members) +NTSTATUS pdb_enum_aliasmem(const DOM_SID *alias, + DOM_SID **pp_members, size_t *p_num_members) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_aliasmem(pdb_context, alias, - pp_members, p_num_members)); + return pdb_context->pdb_enum_aliasmem(pdb_context, alias, + pp_members, p_num_members); } -BOOL pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, - const DOM_SID *members, size_t num_members, - uint32 **pp_alias_rids, size_t *p_num_alias_rids) +NTSTATUS pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + const DOM_SID *members, size_t num_members, + uint32 **pp_alias_rids, + size_t *p_num_alias_rids) { struct pdb_context *pdb_context = pdb_get_static_context(False); if (!pdb_context) { - return False; + return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_IS_OK(pdb_context-> - pdb_enum_alias_memberships(pdb_context, mem_ctx, - domain_sid, - members, num_members, - pp_alias_rids, - p_num_alias_rids)); + return pdb_context->pdb_enum_alias_memberships(pdb_context, mem_ctx, + domain_sid, + members, num_members, + pp_alias_rids, + p_num_alias_rids); } NTSTATUS pdb_lookup_rids(const DOM_SID *domain_sid, @@ -1484,6 +1548,78 @@ BOOL pdb_get_seq_num(time_t *seq_num) return NT_STATUS_IS_OK(pdb_context-> pdb_get_seq_num(pdb_context, seq_num)); } + +BOOL pdb_uid_to_rid(uid_t uid, uint32 *rid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_uid_to_rid(pdb_context, uid, rid); +} + +BOOL pdb_gid_to_sid(gid_t gid, DOM_SID *sid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_gid_to_sid(pdb_context, gid, sid); +} + +BOOL pdb_sid_to_id(const DOM_SID *sid, union unid_t *id, + enum SID_NAME_USE *type) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_sid_to_id(pdb_context, sid, id, type); +} + +BOOL pdb_rid_algorithm(void) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return pdb_context->pdb_rid_algorithm(pdb_context); +} + +BOOL pdb_new_rid(uint32 *rid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + if (pdb_rid_algorithm()) { + DEBUG(0, ("Trying to allocate a RID when algorithmic RIDs " + "are active\n")); + return False; + } + + if (algorithmic_rid_base() != BASE_RID) { + DEBUG(0, ("'algorithmic rid base' is set but a passdb backend " + "without algorithmic RIDs is chosen.\n")); + DEBUGADD(0, ("Please map all used groups using 'net groupmap " + "add', set the maximum used RID using\n")); + DEBUGADD(0, ("'net setmaxrid' and remove the parameter\n")); + return False; + } + + return pdb_context->pdb_new_rid(pdb_context, rid); +} + /*************************************************************** Initialize the static context (at smbd startup etc). @@ -1567,6 +1703,117 @@ static NTSTATUS pdb_default_get_seq_num(struct pdb_methods *methods, time_t *seq return NT_STATUS_OK; } +static BOOL pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid, + uint32 *rid) +{ + SAM_ACCOUNT *sampw = NULL; + struct passwd *unix_pw; + BOOL ret; + + unix_pw = sys_getpwuid( uid ); + + if ( !unix_pw ) { + DEBUG(4,("pdb_default_uid_to_rid: host has no idea of uid " + "%lu\n", (unsigned long)uid)); + return False; + } + + if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { + DEBUG(0,("pdb_default_uid_to_rid: failed to allocate " + "SAM_ACCOUNT object\n")); + return False; + } + + become_root(); + ret = NT_STATUS_IS_OK( + methods->getsampwnam(methods, sampw, unix_pw->pw_name )); + unbecome_root(); + + if (!ret) { + DEBUG(5, ("pdb_default_uid_to_rid: Did not find user " + "%s (%d)\n", unix_pw->pw_name, uid)); + pdb_free_sam(&sampw); + return False; + } + + ret = sid_peek_check_rid(get_global_sam_sid(), + pdb_get_user_sid(sampw), rid); + + if (!ret) { + DEBUG(1, ("Could not peek rid out of sid %s\n", + sid_string_static(pdb_get_user_sid(sampw)))); + } + + pdb_free_sam(&sampw); + return ret; +} + +static BOOL pdb_default_gid_to_sid(struct pdb_methods *methods, gid_t gid, + DOM_SID *sid) +{ + GROUP_MAP map; + + if (!NT_STATUS_IS_OK(methods->getgrgid(methods, &map, gid))) { + return False; + } + + sid_copy(sid, &map.sid); + return True; +} + +static BOOL pdb_default_sid_to_id(struct pdb_methods *methods, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + TALLOC_CTX *mem_ctx; + BOOL ret = False; + const char *name; + uint32 rid; + + mem_ctx = talloc_new(NULL); + + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) { + /* Here we might have users as well as groups and aliases */ + ret = lookup_global_sam_rid(mem_ctx, rid, &name, type, id); + goto done; + } + + if (sid_peek_check_rid(&global_sid_Builtin, sid, &rid)) { + /* Here we only have aliases */ + GROUP_MAP map; + if (!NT_STATUS_IS_OK(methods->getgrsid(methods, &map, *sid))) { + DEBUG(10, ("Could not find map for sid %s\n", + sid_string_static(sid))); + goto done; + } + if ((map.sid_name_use != SID_NAME_ALIAS) && + (map.sid_name_use != SID_NAME_WKN_GRP)) { + DEBUG(10, ("Map for sid %s is a %s, expected an " + "alias\n", sid_string_static(sid), + sid_type_lookup(map.sid_name_use))); + goto done; + } + + id->gid = map.gid; + *type = SID_NAME_ALIAS; + ret = True; + goto done; + } + + DEBUG(5, ("Sid %s is neither ours nor builtin, don't know it\n", + sid_string_static(sid))); + + done: + + talloc_free(mem_ctx); + return ret; +} + static void add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid, uid_t **pp_uids, size_t *p_num) { @@ -1644,7 +1891,7 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, *pp_member_rids = NULL; *p_num_members = 0; - if (!NT_STATUS_IS_OK(sid_to_gid(group, &gid))) + if (!sid_to_gid(group, &gid)) return NT_STATUS_NO_SUCH_GROUP; if(!get_memberuids(mem_ctx, gid, &uids, &num_uids)) @@ -1658,10 +1905,7 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, for (i=0; i EXIT BECOME_ROOT() */ + *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account)); + *psid_name_use = SID_NAME_USER; + + pdb_free_sam(&sam_account); + + if (unix_id == NULL) { + return True; + } + + pw = Get_Pwnam(*name); + if (pw == NULL) { + return False; + } + unix_id->uid = pw->pw_uid; + return True; + } + pdb_free_sam(&sam_account); + + ret = pdb_getgrsid(&map, sid); + unbecome_root(); + /* END BECOME_ROOT BLOCK */ + + if ( ret ) { + if (map.gid!=(gid_t)-1) { + DEBUG(5,("lookup_global_sam_rid: mapped group %s to " + "gid %u\n", map.nt_name, + (unsigned int)map.gid)); + } else { + DEBUG(5,("lookup_global_sam_rid: mapped group %s to " + "no unix gid. Returning name.\n", + map.nt_name)); + } + + *name = talloc_strdup(mem_ctx, map.nt_name); + *psid_name_use = map.sid_name_use; + + if (unix_id == NULL) { + return True; + } + + if (map.gid == (gid_t)-1) { + DEBUG(5, ("Can't find a unix id for an unmapped " + "group\n")); + return False; + } + + unix_id->gid = map.gid; + return True; + } + + return False; +} + NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, const DOM_SID *domain_sid, int num_rids, @@ -1715,7 +2045,8 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, for (i = 0; i < num_rids; i++) { const char *name; - if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i])) { + if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i], + NULL)) { names[i] = name; DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); have_mapped = True; @@ -1772,11 +2103,9 @@ NTSTATUS pdb_default_lookup_names(struct pdb_methods *methods, } for (i = 0; i < num_names; i++) { - const char *name; - - if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i])) { - names[i] = name; - DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i])); + if (lookup_global_sam_name(names[i], 0, &rids[i], &attrs[i])) { + DEBUG(5,("lookup_names: %s-> %d:%d\n", names[i], + rids[i], attrs[i])); have_mapped = True; } else { have_unmapped = True; @@ -2157,6 +2486,9 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*methods)->get_account_policy = pdb_default_get_account_policy; (*methods)->set_account_policy = pdb_default_set_account_policy; (*methods)->get_seq_num = pdb_default_get_seq_num; + (*methods)->uid_to_rid = pdb_default_uid_to_rid; + (*methods)->gid_to_sid = pdb_default_gid_to_sid; + (*methods)->sid_to_id = pdb_default_sid_to_id; (*methods)->search_users = pdb_default_search_users; (*methods)->search_groups = pdb_default_search_groups; diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index b35ce18eee5..a21e9768031 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -84,13 +84,12 @@ #include "smbldap.h" /********************************************************************** - Free a LDAPMessage (one is stored on the SAM_ACCOUNT). + Simple helper function to make stuff better readable **********************************************************************/ - -void private_data_free_fn(void **result) + +static LDAP *priv2ld(struct ldapsam_privates *priv) { - ldap_msgfree(*result); - *result = NULL; + return priv->smbldap_state->ldap_struct; } /********************************************************************** @@ -117,14 +116,14 @@ static const char* get_userattr_key2string( int schema_ver, int key ) Return the list of attribute names given a user schema version. **********************************************************************/ -const char** get_userattr_list( int schema_ver ) +const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver ) { switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: - return get_attr_list( attrib_map_v22 ); + return get_attr_list( mem_ctx, attrib_map_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: - return get_attr_list( attrib_map_v30 ); + return get_attr_list( mem_ctx, attrib_map_v30 ); default: DEBUG(0,("get_userattr_list: unknown schema version specified!\n")); break; @@ -137,14 +136,17 @@ const char** get_userattr_list( int schema_ver ) Return the list of attribute names to delete given a user schema version. **************************************************************************/ -static const char** get_userattr_delete_list( int schema_ver ) +static const char** get_userattr_delete_list( TALLOC_CTX *mem_ctx, + int schema_ver ) { switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: - return get_attr_list( attrib_map_to_delete_v22 ); + return get_attr_list( mem_ctx, + attrib_map_to_delete_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: - return get_attr_list( attrib_map_to_delete_v30 ); + return get_attr_list( mem_ctx, + attrib_map_to_delete_v30 ); default: DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n")); break; @@ -250,13 +252,6 @@ static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_ LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg); if (rc != LDAP_SUCCESS) { - - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(0,("ldapsam_get_seq_num: Failed search for suffix: %s, error: %s (%s)\n", - suffix,ldap_err2string(rc), ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); goto done; } @@ -399,58 +394,37 @@ static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state, object found in search_result depending on lp_ldap_delete_dn ******************************************************************/ -static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, - LDAPMessage *result, - const char *objectclass, - const char **attrs) +static int ldapsam_delete_entry(struct ldapsam_privates *priv, + TALLOC_CTX *mem_ctx, + LDAPMessage *entry, + const char *objectclass, + const char **attrs) { - int rc; - LDAPMessage *entry = NULL; LDAPMod **mods = NULL; - char *name, *dn; + char *name; + const char *dn; BerElement *ptr = NULL; - rc = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); - - if (rc != 1) { - DEBUG(0, ("ldapsam_delete_entry: Entry must exist exactly once!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!dn) { - return NT_STATUS_UNSUCCESSFUL; + dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry); + if (dn == NULL) { + return LDAP_NO_MEMORY; } if (lp_ldap_delete_dn()) { - NTSTATUS ret = NT_STATUS_OK; - rc = smbldap_delete(ldap_state->smbldap_state, dn); - - if (rc != LDAP_SUCCESS) { - DEBUG(0, ("ldapsam_delete_entry: Could not delete object %s\n", dn)); - ret = NT_STATUS_UNSUCCESSFUL; - } - SAFE_FREE(dn); - return ret; + return smbldap_delete(priv->smbldap_state, dn); } /* Ok, delete only the SAM attributes */ - for (name = ldap_first_attribute(ldap_state->smbldap_state->ldap_struct, entry, &ptr); + for (name = ldap_first_attribute(priv2ld(priv), entry, &ptr); name != NULL; - name = ldap_next_attribute(ldap_state->smbldap_state->ldap_struct, entry, ptr)) { + name = ldap_next_attribute(priv2ld(priv), entry, ptr)) { const char **attrib; /* We are only allowed to delete the attributes that really exist. */ for (attrib = attrs; *attrib != NULL; attrib++) { - /* Don't delete LDAP_ATTR_MOD_TIMESTAMP attribute. */ - if (strequal(*attrib, get_userattr_key2string(ldap_state->schema_ver, - LDAP_ATTR_MOD_TIMESTAMP))) { - continue; - } if (strequal(*attrib, name)) { DEBUG(10, ("ldapsam_delete_entry: deleting " "attribute %s\n", name)); @@ -458,33 +432,17 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, NULL); } } - ldap_memfree(name); } - + if (ptr != NULL) { ber_free(ptr, 0); } smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass); - - rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - ldap_mods_free(mods, True); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - - DEBUG(0, ("ldapsam_delete_entry: Could not delete attributes for %s, error: %s (%s)\n", - dn, ldap_err2string(rc), ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); - SAFE_FREE(dn); - return NT_STATUS_UNSUCCESSFUL; - } - - SAFE_FREE(dn); - return NT_STATUS_OK; + talloc_autofree_ldapmod(mem_ctx, mods); + + return smbldap_modify(priv->smbldap_state, dn, mods); } /* New Interface is being implemented here */ @@ -627,13 +585,16 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, return False; } - if (ldap_state->smbldap_state->ldap_struct == NULL) { - DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->ldap_struct is NULL!\n")); + if (priv2ld(ldap_state) == NULL) { + DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->" + "ldap_struct is NULL!\n")); return False; } - if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, "uid", username)) { - DEBUG(1, ("init_sam_from_ldap: No uid attribute found for this user!\n")); + if (!smbldap_get_single_pstring(priv2ld(ldap_state), entry, "uid", + username)) { + DEBUG(1, ("init_sam_from_ldap: No uid attribute found for " + "this user!\n")); return False; } @@ -992,6 +953,15 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, ZERO_STRUCT(hours); } + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + if (smbldap_get_single_pstring(priv2ld(ldap_state), entry, + "uidNumber", temp)) { + /* We've got a uid, feed the cache */ + uid_t uid = strtoul(temp, NULL, 10); + store_uid_sid_cache(pdb_get_user_sid(sampass), uid); + } + } + /* check the timestamp of the cache vs ldap entry */ if (!(ldap_entry_time = ldapsam_get_entry_timestamp(ldap_state, entry))) @@ -1380,10 +1350,10 @@ static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update, DEBUG(10,("ldapsam_setsampwent: LDAP Query for acb_mask 0x%x will use suffix %s\n", acb_mask, suffix)); - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = smbldap_search(ldap_state->smbldap_state, suffix, LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &ldap_state->result); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { DEBUG(0, ("ldapsam_setsampwent: LDAP search failed: %s\n", ldap_err2string(rc))); @@ -1421,10 +1391,12 @@ static void ldapsam_endsampwent(struct pdb_methods *my_methods) Get the next entry in the LDAP password database. *********************************************************************/ -static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) +static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, + SAM_ACCOUNT *user) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; BOOL bret = False; while (!bret) { @@ -1434,14 +1406,15 @@ static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT ldap_state->index++; bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry); - ldap_state->entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct, - ldap_state->entry); + ldap_state->entry = ldap_next_entry(priv2ld(ldap_state), + ldap_state->entry); } return NT_STATUS_OK; } -static void append_attr(const char ***attr_list, const char *new_attr) +static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list, + const char *new_attr) { int i; @@ -1453,9 +1426,10 @@ static void append_attr(const char ***attr_list, const char *new_attr) ; } - (*attr_list) = SMB_REALLOC_ARRAY((*attr_list), const char *, i+2); + (*attr_list) = TALLOC_REALLOC_ARRAY(mem_ctx, (*attr_list), + const char *, i+2); SMB_ASSERT((*attr_list) != NULL); - (*attr_list)[i] = SMB_STRDUP(new_attr); + (*attr_list)[i] = talloc_strdup((*attr_list), new_attr); (*attr_list)[i+1] = NULL; } @@ -1473,10 +1447,14 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT const char ** attr_list; int rc; - attr_list = get_userattr_list( ldap_state->schema_ver ); - append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); - rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); - free_attr_list( attr_list ); + attr_list = get_userattr_list( user->mem_ctx, ldap_state->schema_ver ); + append_attr(user->mem_ctx, &attr_list, + get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP)); + append_attr(user->mem_ctx, &attr_list, "uidNumber"); + rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, + attr_list); + talloc_free( attr_list ); if ( rc != LDAP_SUCCESS ) return NT_STATUS_NO_SUCH_USER; @@ -1500,9 +1478,9 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT ldap_msgfree(result); return NT_STATUS_NO_SUCH_USER; } - pdb_set_backend_private_data(user, result, - private_data_free_fn, + pdb_set_backend_private_data(user, result, NULL, my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(user->mem_ctx, result); ret = NT_STATUS_OK; } else { ldap_msgfree(result); @@ -1518,24 +1496,37 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, uint32 rid; switch ( ldap_state->schema_ver ) { - case SCHEMAVER_SAMBASAMACCOUNT: - attr_list = get_userattr_list(ldap_state->schema_ver); - append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); - rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list); - free_attr_list( attr_list ); + case SCHEMAVER_SAMBASAMACCOUNT: { + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return LDAP_NO_MEMORY; + } + + attr_list = get_userattr_list(tmp_ctx, + ldap_state->schema_ver); + append_attr(tmp_ctx, &attr_list, + get_userattr_key2string( + ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP)); + append_attr(tmp_ctx, &attr_list, "uidNumber"); + rc = ldapsam_search_suffix_by_sid(ldap_state, sid, + result, attr_list); + talloc_free(tmp_ctx); if ( rc != LDAP_SUCCESS ) return rc; break; + } case SCHEMAVER_SAMBAACCOUNT: if (!sid_peek_check_rid(&ldap_state->domain_sid, sid, &rid)) { return rc; } - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, + ldap_state->schema_ver); rc = ldapsam_search_suffix_by_rid(ldap_state, rid, result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if ( rc != LDAP_SUCCESS ) return rc; @@ -1588,9 +1579,9 @@ static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT return NT_STATUS_NO_SUCH_USER; } - pdb_set_backend_private_data(user, result, - private_data_free_fn, + pdb_set_backend_private_data(user, result, NULL, my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(user->mem_ctx, result); return NT_STATUS_OK; } @@ -1639,14 +1630,6 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, } if (rc!=LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(1, ("ldapsam_modify_entry: Failed to %s user dn= %s with: %s\n\t%s\n", - ldap_op == LDAP_MOD_ADD ? "add" : "modify", - dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return NT_STATUS_UNSUCCESSFUL; } } @@ -1747,15 +1730,17 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, Delete entry from LDAP for username. *********************************************************************/ -static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct) +static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, + SAM_ACCOUNT * sam_acct) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *priv = + (struct ldapsam_privates *)my_methods->private_data; const char *sname; int rc; - LDAPMessage *result = NULL; - NTSTATUS ret; + LDAPMessage *msg, *entry; + NTSTATUS result = NT_STATUS_NO_MEMORY; const char **attr_list; - fstring objclass; + TALLOC_CTX *mem_ctx; if (!sam_acct) { DEBUG(0, ("ldapsam_delete_sam_account: sam_acct was NULL!\n")); @@ -1764,35 +1749,42 @@ static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_A sname = pdb_get_username(sam_acct); - DEBUG (3, ("ldapsam_delete_sam_account: Deleting user %s from LDAP.\n", sname)); + DEBUG(3, ("ldapsam_delete_sam_account: Deleting user %s from " + "LDAP.\n", sname)); - attr_list= get_userattr_delete_list( ldap_state->schema_ver ); - rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + goto done; + } - if (rc != LDAP_SUCCESS) { - free_attr_list( attr_list ); - return NT_STATUS_NO_SUCH_USER; + attr_list = get_userattr_delete_list(mem_ctx, priv->schema_ver ); + if (attr_list == NULL) { + goto done; } - - switch ( ldap_state->schema_ver ) { - case SCHEMAVER_SAMBASAMACCOUNT: - fstrcpy( objclass, LDAP_OBJ_SAMBASAMACCOUNT ); - break; - - case SCHEMAVER_SAMBAACCOUNT: - fstrcpy( objclass, LDAP_OBJ_SAMBAACCOUNT ); - break; - default: - fstrcpy( objclass, "UNKNOWN" ); - DEBUG(0,("ldapsam_delete_sam_account: Unknown schema version specified!\n")); - break; + + rc = ldapsam_search_suffix_by_name(priv, sname, &msg, attr_list); + + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(priv2ld(priv), msg) != 1) || + ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) { + DEBUG(5, ("Could not find user %s\n", sname)); + result = NT_STATUS_NO_SUCH_USER; + goto done; } + + rc = ldapsam_delete_entry( + priv, mem_ctx, entry, + priv->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ? + LDAP_OBJ_SAMBASAMACCOUNT : LDAP_OBJ_SAMBAACCOUNT, + attr_list); - ret = ldapsam_delete_entry(ldap_state, result, objclass, attr_list ); - ldap_msgfree(result); - free_attr_list( attr_list ); + result = (rc == LDAP_SUCCESS) ? + NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; - return ret; + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** @@ -1823,13 +1815,15 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A result = pdb_get_backend_private_data(newpwd, my_methods); if (!result) { - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; } - pdb_set_backend_private_data(newpwd, result, private_data_free_fn, my_methods, PDB_CHANGED); + pdb_set_backend_private_data(newpwd, result, NULL, + my_methods, PDB_CHANGED); + talloc_autofree_ldapmsg(newpwd->mem_ctx, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { @@ -1866,12 +1860,6 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A SAFE_FREE(dn); if (!NT_STATUS_IS_OK(ret)) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0,("ldapsam_update_sam_account: failed to modify user with uid = %s, error: %s (%s)\n", - pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc))); - SAFE_FREE(ld_error); return ret; } @@ -1966,12 +1954,12 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO } /* free this list after the second search or in case we exit on failure */ - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list); if (rc != LDAP_SUCCESS) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -1979,7 +1967,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO DEBUG(0,("ldapsam_add_sam_account: User '%s' already in the base, with samba attributes\n", username)); ldap_msgfree(result); - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } ldap_msgfree(result); @@ -1992,7 +1980,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) { DEBUG(0,("ldapsam_add_sam_account: SID '%s' already in the base, with samba attributes\n", sid_to_string(sid_string, sid))); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2011,7 +1999,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, attr_list, &result); if ( rc != LDAP_SUCCESS ) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -2019,7 +2007,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (num_result > 1) { DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n")); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2033,7 +2021,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry); if (!tmp) { - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2059,7 +2047,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO filter, attr_list, &result); if ( rc != LDAP_SUCCESS ) { - free_attr_list( attr_list ); + talloc_free( attr_list ); return NT_STATUS_UNSUCCESSFUL; } @@ -2067,7 +2055,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO if (num_result > 1) { DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n")); - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2081,7 +2069,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry); if (!tmp) { - free_attr_list( attr_list ); + talloc_free( attr_list ); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -2090,7 +2078,7 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO } } - free_attr_list( attr_list ); + talloc_free( attr_list ); if (num_result == 0) { /* Check if we need to add an entry */ @@ -2155,23 +2143,11 @@ static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state, int rc; const char **attr_list; - attr_list = get_attr_list(groupmap_attr_list); + attr_list = get_attr_list(NULL, groupmap_attr_list); rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix (), scope, filter, attr_list, 0, result); - free_attr_list( attr_list ); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_search_one_group: " - "Problem during the LDAP search: LDAP error: %s (%s)\n", - ld_error?ld_error:"(unknown)", ldap_err2string(rc))); - DEBUGADD(3, ("ldapsam_search_one_group: Query was: %s, %s\n", - lp_ldap_group_suffix(), filter)); - SAFE_FREE(ld_error); - } + talloc_free(attr_list); return rc; } @@ -2245,39 +2221,10 @@ for gidNumber(%lu)\n",(unsigned long)map->gid)); } fstrcpy(map->comment, temp); - return True; -} - -/********************************************************************** - *********************************************************************/ - -static BOOL init_ldap_from_group(LDAP *ldap_struct, - LDAPMessage *existing, - LDAPMod ***mods, - const GROUP_MAP *map) -{ - pstring tmp; - - if (mods == NULL || map == NULL) { - DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n")); - return False; + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + store_gid_sid_cache(&map->sid, map->gid); } - *mods = NULL; - - sid_to_string(tmp, &map->sid); - - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID), tmp); - pstr_sprintf(tmp, "%i", map->sid_name_use); - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), tmp); - - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), map->nt_name); - smbldap_make_mod(ldap_struct, existing, mods, - get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), map->comment); - return True; } @@ -2299,7 +2246,7 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, return NT_STATUS_NO_SUCH_GROUP; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + count = ldap_count_entries(priv2ld(ldap_state), result); if (count < 1) { DEBUG(4, ("ldapsam_getgroup: Did not find group\n")); @@ -2308,13 +2255,13 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: count=%d\n", - filter, count)); + DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: " + "count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_GROUP; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(priv2ld(ldap_state), result); if (!entry) { ldap_msgfree(result); @@ -2322,8 +2269,8 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, } if (!init_group_from_ldap(ldap_state, map, entry)) { - DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for group filter %s\n", - filter)); + DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for " + "group filter %s\n", filter)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_GROUP; } @@ -2458,11 +2405,6 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, char *tmp; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_enum_group_members(methods, mem_ctx, group, - pp_member_rids, - p_num_members); - *pp_member_rids = NULL; *p_num_members = 0; @@ -2618,9 +2560,10 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, } static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, - const char *username, - gid_t primary_gid, - DOM_SID **pp_sids, gid_t **pp_gids, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, size_t *p_num_groups) { struct ldapsam_privates *ldap_state = @@ -2634,23 +2577,24 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, LDAPMessage *entry; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; size_t num_sids, num_gids; - - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_enum_group_memberships(methods, username, - primary_gid, pp_sids, - pp_gids, p_num_groups); + gid_t primary_gid; *pp_sids = NULL; num_sids = 0; - escape_name = escape_ldap_string_alloc(username); + if (!sid_to_gid(pdb_get_group_sid(user), &primary_gid)) { + DEBUG(1, ("sid_to_gid failed for user's primary group\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + escape_name = escape_ldap_string_alloc(pdb_get_username(user)); if (escape_name == NULL) return NT_STATUS_NO_MEMORY; pstr_sprintf(filter, "(&(objectClass=posixGroup)" "(|(memberUid=%s)(gidNumber=%d)))", - username, primary_gid); + escape_name, primary_gid); rc = smbldap_search(conn, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg); @@ -2666,11 +2610,11 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, /* We need to add the primary group as the first gid/sid */ - add_gid_to_array_unique(NULL, primary_gid, pp_gids, &num_gids); + add_gid_to_array_unique(mem_ctx, primary_gid, pp_gids, &num_gids); /* This sid will be replaced later */ - add_sid_to_array_unique(NULL, &global_sid_NULL, pp_sids, &num_sids); + add_sid_to_array_unique(mem_ctx, &global_sid_NULL, pp_sids, &num_sids); for (entry = ldap_first_entry(conn->ldap_struct, msg); entry != NULL; @@ -2702,13 +2646,16 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, if (gid == primary_gid) { sid_copy(&(*pp_sids)[0], &sid); } else { - add_gid_to_array_unique(NULL, gid, pp_gids, &num_gids); - add_sid_to_array_unique(NULL, &sid, pp_sids, &num_sids); + add_gid_to_array_unique(mem_ctx, gid, pp_gids, + &num_gids); + add_sid_to_array_unique(mem_ctx, &sid, pp_sids, + &num_sids); } } if (sid_compare(&global_sid_NULL, &(*pp_sids)[0]) == 0) { - DEBUG(3, ("primary group of [%s] not found\n", username)); + DEBUG(3, ("primary group of [%s] not found\n", + pdb_get_username(user))); goto done; } @@ -2726,143 +2673,203 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods, } /********************************************************************** + * Augment a posixGroup object with a sambaGroupMapping domgroup *********************************************************************/ -static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state, - gid_t gid, - LDAPMessage **result) +static NTSTATUS ldapsam_map_posixgroup(TALLOC_CTX *mem_ctx, + struct ldapsam_privates *ldap_state, + GROUP_MAP *map) { - pstring filter; + const char *filter, *dn; + LDAPMessage *msg, *entry; + LDAPMod **mods; + int rc; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%lu))", - LDAP_OBJ_POSIXGROUP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), - (unsigned long)gid); + filter = talloc_asprintf(mem_ctx, + "(&(objectClass=posixGroup)(gidNumber=%u))", + map->gid); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } - return ldapsam_search_one_group(ldap_state, filter, result); -} + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); -/********************************************************************** - *********************************************************************/ + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) || + ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) { + return NT_STATUS_NO_SUCH_GROUP; + } + + dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry); + if (dn == NULL) { + return NT_STATUS_NO_MEMORY; + } + + mods = NULL; + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", + "sambaGroupMapping"); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaSid", + sid_string_static(&map->sid)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaGroupType", + talloc_asprintf(mem_ctx, "%d", map->sid_name_use)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description", + map->comment); + talloc_autofree_ldapmod(mem_ctx, mods); + + rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); + if (rc != LDAP_SUCCESS) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods, GROUP_MAP *map) { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - LDAPMessage *result = NULL; + LDAPMessage *msg = NULL; LDAPMod **mods = NULL; - int count; + const char *attrs[] = { NULL }; + char *filter; - char *tmp; - pstring dn; - LDAPMessage *entry; + char *dn; + TALLOC_CTX *mem_ctx; + NTSTATUS result; - GROUP_MAP dummy; + DOM_SID sid; int rc; - if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy, - map->gid))) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: Group %ld already exists in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_UNSUCCESSFUL; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; } - rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result); - if (rc != LDAP_SUCCESS) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + filter = talloc_asprintf(mem_ctx, "(sambaSid=%s)", + sid_string_static(&map->sid)); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(), + LDAP_SCOPE_SUBTREE, filter, attrs, True, &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); - if ( count == 0 ) { - /* There's no posixGroup account, let's try to find an - * appropriate idmap entry for aliases */ - - pstring suffix; - pstring filter; - const char **attr_list; - - ldap_msgfree(result); + if ((rc == LDAP_SUCCESS) && + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) > 0)) { - pstrcpy( suffix, lp_ldap_idmap_suffix() ); - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%u))", - LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_GIDNUMBER, - map->gid); - - attr_list = get_attr_list( sidmap_attr_list ); - rc = smbldap_search(ldap_state->smbldap_state, suffix, - LDAP_SCOPE_SUBTREE, filter, attr_list, - 0, &result); + DEBUG(3, ("SID %s already present in LDAP, refusing to add " + "group mapping entry\n", + sid_string_static(&map->sid))); + result = NT_STATUS_GROUP_EXISTS; + goto done; + } - free_attr_list(attr_list); + switch (map->sid_name_use) { - if (rc != LDAP_SUCCESS) { - DEBUG(3,("Failure looking up entry (%s)\n", - ldap_err2string(rc) )); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + case SID_NAME_DOM_GRP: + /* To map a domain group we need to have a posix group + to attach to. */ + result = ldapsam_map_posixgroup(mem_ctx, ldap_state, map); + goto done; + break; + + case SID_NAME_ALIAS: + if (!sid_check_is_in_our_domain(&map->sid)) { + DEBUG(3, ("Refusing to map sid %s as an alias, not " + "in our domain\n", + sid_string_static(&map->sid))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - } - - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); - if ( count == 0 ) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; - } + break; + + case SID_NAME_WKN_GRP: + if (!sid_check_is_in_builtin(&map->sid)) { + DEBUG(3, ("Refusing to map sid %s as an alias, not " + "in builtin domain\n", + sid_string_static(&map->sid))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + break; - if (count > 1) { - DEBUG(2, ("ldapsam_add_group_mapping_entry: Group %lu must exist exactly once in LDAP\n", - (unsigned long)map->gid)); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + default: + DEBUG(3, ("Got invalid use '%s' for mapping\n", + sid_type_lookup(map->sid_name_use))); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - tmp = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!tmp) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + /* Domain groups have been mapped in a separate routine, we have to + * create an alias now */ + + if (map->gid == -1) { + DEBUG(10, ("Refusing to map gid==-1\n")); + result = NT_STATUS_INVALID_PARAMETER; + goto done; } - pstrcpy(dn, tmp); - SAFE_FREE(tmp); - if (!init_ldap_from_group(ldap_state->smbldap_state->ldap_struct, - result, &mods, map)) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: init_ldap_from_group failed!\n")); - ldap_mods_free(mods, True); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + if (pdb_gid_to_sid(map->gid, &sid)) { + DEBUG(3, ("Gid %d is already mapped to SID %s, refusing to " + "add\n", map->gid, sid_string_static(&sid))); + result = NT_STATUS_GROUP_EXISTS; + goto done; } - ldap_msgfree(result); + /* Ok, enough checks done. It's still racy to go ahead now, but that's + * the best we can get out of LDAP. */ - if (mods == NULL) { - DEBUG(0, ("ldapsam_add_group_mapping_entry: mods is empty\n")); - return NT_STATUS_UNSUCCESSFUL; + dn = talloc_asprintf(mem_ctx, "sambaSid=%s,%s", + sid_string_static(&map->sid), + lp_ldap_group_suffix()); + if (dn == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP ); + mods = NULL; - rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - ldap_mods_free(mods, True); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass", + "sambaSidEntry"); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "objectClass", + "sambaGroupMapping"); - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_add_group_mapping_entry: failed to add group %lu error: %s (%s)\n", (unsigned long)map->gid, - ld_error ? ld_error : "(unknown)", ldap_err2string(rc))); - SAFE_FREE(ld_error); - return NT_STATUS_UNSUCCESSFUL; - } + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaSid", + sid_string_static(&map->sid)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "sambaGroupType", + talloc_asprintf(mem_ctx, "%d", map->sid_name_use)); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "description", + map->comment); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, NULL, &mods, "gidNumber", + talloc_asprintf(mem_ctx, "%u", map->gid)); + talloc_autofree_ldapmod(mem_ctx, mods); - DEBUG(2, ("ldapsam_add_group_mapping_entry: successfully modified group %lu in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_OK; + rc = smbldap_add(ldap_state->smbldap_state, dn, mods); + + result = (rc == LDAP_SUCCESS) ? + NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** + * Update a group mapping entry. We're quite strict about what can be changed: + * Only the description and displayname may be changed. It simply does not + * make any sense to change the SID, gid or the type in a mapping. *********************************************************************/ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, @@ -2871,63 +2878,80 @@ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; int rc; - char *dn = NULL; - LDAPMessage *result = NULL; + const char *filter, *dn; + LDAPMessage *msg = NULL; LDAPMessage *entry = NULL; LDAPMod **mods = NULL; + TALLOC_CTX *mem_ctx; + NTSTATUS result; - rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } - if (rc != LDAP_SUCCESS) { - return NT_STATUS_UNSUCCESSFUL; + /* Make 100% sure that sid, gid and type are not changed by looking up + * exactly the values we're given in LDAP. */ + + filter = talloc_asprintf(mem_ctx, "(&(objectClass=sambaGroupMapping)" + "(sambaSid=%s)(gidNumber=%u)" + "(sambaGroupType=%d))", + sid_string_static(&map->sid), map->gid, + map->sid_name_use); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } - if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { - DEBUG(0, ("ldapsam_update_group_mapping_entry: No group to modify!\n")); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; + rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); + + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) || + ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) { + result = NT_STATUS_NO_SUCH_GROUP; + goto done; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry); - if (!init_ldap_from_group(ldap_state->smbldap_state->ldap_struct, - result, &mods, map)) { - DEBUG(0, ("ldapsam_update_group_mapping_entry: init_ldap_from_group failed\n")); - ldap_msgfree(result); - if (mods != NULL) - ldap_mods_free(mods,True); - return NT_STATUS_UNSUCCESSFUL; + if (dn == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; } + mods = NULL; + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName", + map->nt_name); + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "description", + map->comment); + talloc_autofree_ldapmod(mem_ctx, mods); + if (mods == NULL) { - DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: nothing to do\n")); - ldap_msgfree(result); - return NT_STATUS_OK; + DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: " + "nothing to do\n")); + result = NT_STATUS_OK; + goto done; } - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!dn) { - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; - } rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - SAFE_FREE(dn); - - ldap_mods_free(mods, True); - ldap_msgfree(result); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(0, ("ldapsam_update_group_mapping_entry: failed to modify group %lu error: %s (%s)\n", (unsigned long)map->gid, - ld_error ? ld_error : "(unknown)", ldap_err2string(rc))); - SAFE_FREE(ld_error); - return NT_STATUS_UNSUCCESSFUL; + result = NT_STATUS_ACCESS_DENIED; + goto done; } - DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified group %lu in LDAP\n", (unsigned long)map->gid)); - return NT_STATUS_OK; + DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified " + "group %lu in LDAP\n", (unsigned long)map->gid)); + + result = NT_STATUS_OK; + + done: + talloc_free(mem_ctx); + return result; } /********************************************************************** @@ -2936,53 +2960,103 @@ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods, static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods, DOM_SID sid) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - pstring sidstring, filter; - LDAPMessage *result = NULL; + struct ldapsam_privates *priv = + (struct ldapsam_privates *)methods->private_data; + LDAPMessage *msg, *entry; int rc; - NTSTATUS ret; - const char **attr_list; + NTSTATUS result; + TALLOC_CTX *mem_ctx; + char *filter; - sid_to_string(sidstring, &sid); - - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, sidstring); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } - rc = ldapsam_search_one_group(ldap_state, filter, &result); + filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))", + LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, + sid_string_static(&sid)); + if (filter == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + rc = smbldap_search_suffix(priv->smbldap_state, filter, + get_attr_list(mem_ctx, groupmap_attr_list), + &msg); + talloc_autofree_ldapmsg(mem_ctx, msg); - if (rc != LDAP_SUCCESS) { - return NT_STATUS_NO_SUCH_GROUP; + if ((rc != LDAP_SUCCESS) || + (ldap_count_entries(priv2ld(priv), msg) != 1) || + ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) { + result = NT_STATUS_NO_SUCH_GROUP; + goto done; + } + + rc = ldapsam_delete_entry(priv, mem_ctx, entry, LDAP_OBJ_GROUPMAP, + get_attr_list(mem_ctx, + groupmap_attr_list_to_delete)); + + if ((rc == LDAP_NAMING_VIOLATION) || + (rc == LDAP_OBJECT_CLASS_VIOLATION)) { + const char *attrs[] = { "sambaGroupType", "description", + "displayName", "sambaSIDList", + NULL }; + + /* Second try. Don't delete the sambaSID attribute, this is + for "old" entries that are tacked on a winbind + sambaIdmapEntry. */ + + rc = ldapsam_delete_entry(priv, mem_ctx, entry, + LDAP_OBJ_GROUPMAP, attrs); } - attr_list = get_attr_list( groupmap_attr_list_to_delete ); - ret = ldapsam_delete_entry(ldap_state, result, LDAP_OBJ_GROUPMAP, attr_list); - free_attr_list ( attr_list ); + if ((rc == LDAP_NAMING_VIOLATION) || + (rc == LDAP_OBJECT_CLASS_VIOLATION)) { + const char *attrs[] = { "sambaGroupType", "description", + "displayName", "sambaSIDList", + "gidNumber", NULL }; - ldap_msgfree(result); + /* Third try. This is a post-3.0.21 alias (containing only + * sambaSidEntry and sambaGroupMapping classes), we also have + * to delete the gidNumber attribute, only the sambaSidEntry + * remains */ - return ret; -} + rc = ldapsam_delete_entry(priv, mem_ctx, entry, + LDAP_OBJ_GROUPMAP, attrs); + } + + result = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + + done: + talloc_free(mem_ctx); + return result; + } /********************************************************************** *********************************************************************/ -static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update) +static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, + BOOL update) { - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; fstring filter; int rc; const char **attr_list; pstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_GROUPMAP); - attr_list = get_attr_list( groupmap_attr_list ); + attr_list = get_attr_list( NULL, groupmap_attr_list ); rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &ldap_state->result); - free_attr_list( attr_list ); + talloc_free(attr_list); if (rc != LDAP_SUCCESS) { - DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n", ldap_err2string(rc))); - DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n", lp_ldap_group_suffix(), filter)); + DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n", + ldap_err2string(rc))); + DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n", + lp_ldap_group_suffix(), filter)); ldap_msgfree(ldap_state->result); ldap_state->result = NULL; return NT_STATUS_UNSUCCESSFUL; @@ -2992,7 +3066,9 @@ static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update) ldap_count_entries(ldap_state->smbldap_state->ldap_struct, ldap_state->result))); - ldap_state->entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, ldap_state->result); + ldap_state->entry = + ldap_first_entry(ldap_state->smbldap_state->ldap_struct, + ldap_state->result); ldap_state->index = 0; return NT_STATUS_OK; @@ -3013,7 +3089,8 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, GROUP_MAP *map) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)my_methods->private_data; BOOL bret = False; while (!bret) { @@ -3021,10 +3098,12 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, return ret; ldap_state->index++; - bret = init_group_from_ldap(ldap_state, map, ldap_state->entry); + bret = init_group_from_ldap(ldap_state, map, + ldap_state->entry); - ldap_state->entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct, - ldap_state->entry); + ldap_state->entry = + ldap_next_entry(ldap_state->smbldap_state->ldap_struct, + ldap_state->entry); } return NT_STATUS_OK; @@ -3035,7 +3114,8 @@ static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods, static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods, enum SID_NAME_USE sid_name_use, - GROUP_MAP **pp_rmap, size_t *p_num_entries, + GROUP_MAP **pp_rmap, + size_t *p_num_entries, BOOL unix_only) { GROUP_MAP map; @@ -3046,24 +3126,28 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods, *pp_rmap = NULL; if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) { - DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open passdb\n")); + DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open " + "passdb\n")); return NT_STATUS_ACCESS_DENIED; } while (NT_STATUS_IS_OK(ldapsam_getsamgrent(methods, &map))) { if (sid_name_use != SID_NAME_UNKNOWN && sid_name_use != map.sid_name_use) { - DEBUG(11,("ldapsam_enum_group_mapping: group %s is not of the requested type\n", map.nt_name)); + DEBUG(11,("ldapsam_enum_group_mapping: group %s is " + "not of the requested type\n", map.nt_name)); continue; } if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) { - DEBUG(11,("ldapsam_enum_group_mapping: group %s is non mapped\n", map.nt_name)); + DEBUG(11,("ldapsam_enum_group_mapping: group %s is " + "non mapped\n", map.nt_name)); continue; } mapt=SMB_REALLOC_ARRAY((*pp_rmap), GROUP_MAP, entries+1); if (!mapt) { - DEBUG(0,("ldapsam_enum_group_mapping: Unable to enlarge group map!\n")); + DEBUG(0,("ldapsam_enum_group_mapping: Unable to " + "enlarge group map!\n")); SAFE_FREE(*pp_rmap); return NT_STATUS_UNSUCCESSFUL; } @@ -3095,14 +3179,28 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, int count; LDAPMod **mods = NULL; int rc; + enum SID_NAME_USE type = SID_NAME_USE_NONE; pstring filter; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, - LDAP_ATTR_GROUP_SID), - sid_string_static(alias)); + if (sid_check_is_in_builtin(alias)) { + type = SID_NAME_WKN_GRP; + } + + if (sid_check_is_in_our_domain(alias)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n", + sid_string_static(alias))); + return NT_STATUS_NO_SUCH_ALIAS; + } + + pstr_sprintf(filter, + "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))", + LDAP_OBJ_GROUPMAP, sid_string_static(alias), + type); if (ldapsam_search_one_group(ldap_state, filter, &result) != LDAP_SUCCESS) @@ -3118,8 +3216,8 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for filter %s: " - "count=%d\n", filter, count)); + DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for " + "filter %s: count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_ALIAS; } @@ -3147,22 +3245,20 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, ldap_mods_free(mods, True); ldap_msgfree(result); + SAFE_FREE(dn); + + if (rc == LDAP_TYPE_OR_VALUE_EXISTS) { + return NT_STATUS_MEMBER_IN_ALIAS; + } + + if (rc == LDAP_NO_SUCH_ATTRIBUTE) { + return NT_STATUS_MEMBER_NOT_IN_ALIAS; + } if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(0, ("ldapsam_modify_aliasmem: Could not modify alias " - "for %s, error: %s (%s)\n", dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); - SAFE_FREE(dn); return NT_STATUS_UNSUCCESSFUL; } - SAFE_FREE(dn); - return NT_STATUS_OK; } @@ -3182,7 +3278,8 @@ static NTSTATUS ldapsam_del_aliasmem(struct pdb_methods *methods, } static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, - const DOM_SID *alias, DOM_SID **pp_members, + const DOM_SID *alias, + DOM_SID **pp_members, size_t *p_num_members) { struct ldapsam_privates *ldap_state = @@ -3194,15 +3291,29 @@ static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, int i; pstring filter; size_t num_members = 0; + enum SID_NAME_USE type = SID_NAME_USE_NONE; *pp_members = NULL; *p_num_members = 0; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY, - get_attr_key2string(groupmap_attr_list, - LDAP_ATTR_GROUP_SID), - sid_string_static(alias)); + if (sid_check_is_in_builtin(alias)) { + type = SID_NAME_WKN_GRP; + } + + if (sid_check_is_in_our_domain(alias)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n", + sid_string_static(alias))); + return NT_STATUS_NO_SUCH_ALIAS; + } + + pstr_sprintf(filter, + "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))", + LDAP_OBJ_GROUPMAP, sid_string_static(alias), + type); if (ldapsam_search_one_group(ldap_state, filter, &result) != LDAP_SUCCESS) @@ -3218,8 +3329,8 @@ static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods, } if (count > 1) { - DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for filter %s: " - "count=%d\n", filter, count)); + DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for " + "filter %s: count=%d\n", filter, count)); ldap_msgfree(result); return NT_STATUS_NO_SUCH_ALIAS; } @@ -3279,14 +3390,25 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods, int i; int rc; char *filter; + enum SID_NAME_USE type = SID_NAME_USE_NONE; + + if (sid_check_is_builtin(domain_sid)) { + type = SID_NAME_WKN_GRP; + } - /* This query could be further optimized by adding a - (&(sambaSID=*)) so that only those aliases that are - asked for in the getuseraliases are returned. */ + if (sid_check_is_domain(domain_sid)) { + type = SID_NAME_ALIAS; + } + + if (type == SID_NAME_USE_NONE) { + DEBUG(5, ("SID %s is neither builtin nor domain!\n", + sid_string_static(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } filter = talloc_asprintf(mem_ctx, - "(&(|(objectclass=%s)(objectclass=%s))(|", - LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY); + "(&(|(objectclass=%s)(sambaGroupType=%d))(|", + LDAP_OBJ_GROUPMAP, type); for (i=0; ismbldap_state, ldap_state->domain_dn, mods); + rc = smbldap_modify(ldap_state->smbldap_state, ldap_state->domain_dn, + mods); ldap_mods_free(mods, True); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(0, ("ldapsam_set_account_policy_in_ldap: Could not set account policy " - "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return ntstatus; } if (!cache_account_policy_set(policy_index, value)) { - DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to update local tdb cache\n")); + DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to " + "update local tdb cache\n")); return ntstatus; } return NT_STATUS_OK; } -static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods, int policy_index, uint32 value) +static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods, + int policy_index, uint32 value) { if (!account_policy_migrated(False)) { - return (account_policy_set(policy_index, value)) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return (account_policy_set(policy_index, value)) ? + NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } - return ldapsam_set_account_policy_in_ldap(methods, policy_index, value); + return ldapsam_set_account_policy_in_ldap(methods, policy_index, + value); } -static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods, int policy_index, uint32 *value) +static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods, + int policy_index, + uint32 *value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; LDAPMessage *result = NULL; @@ -3419,7 +3543,8 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods policy_attr = get_account_policy_attr(policy_index); if (!policy_attr) { - DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid policy index: %d\n", policy_index)); + DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid " + "policy index: %d\n", policy_index)); return ntstatus; } @@ -3427,31 +3552,24 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods attrs[1] = NULL; rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn, - LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &result); + LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, + &result); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING,&ld_error); - - DEBUG(3, ("ldapsam_get_account_policy_from_ldap: Could not get account policy " - "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); return ntstatus; } - count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + count = ldap_count_entries(priv2ld(ldap_state), result); if (count < 1) { goto out; } - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(priv2ld(ldap_state), result); if (entry == NULL) { goto out; } - vals = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, policy_attr); + vals = ldap_get_values(priv2ld(ldap_state), entry, policy_attr); if (vals == NULL) { goto out; } @@ -3470,7 +3588,8 @@ out: /* wrapper around ldapsam_get_account_policy_from_ldap(), handles tdb as cache - - if user hasn't decided to use account policies inside LDAP just reuse the old tdb values + - if user hasn't decided to use account policies inside LDAP just reuse the + old tdb values - if there is a valid cache entry, return that - if there is an LDAP entry, update cache and return @@ -3478,32 +3597,38 @@ out: Guenther */ -static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value) +static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, + int policy_index, uint32 *value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; if (!account_policy_migrated(False)) { - return (account_policy_get(policy_index, value)) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return (account_policy_get(policy_index, value)) + ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } if (cache_account_policy_get(policy_index, value)) { - DEBUG(11,("ldapsam_get_account_policy: got valid value from cache\n")); + DEBUG(11,("ldapsam_get_account_policy: got valid value from " + "cache\n")); return NT_STATUS_OK; } - ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index, value); + ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index, + value); if (NT_STATUS_IS_OK(ntstatus)) { goto update_cache; } - DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from ldap\n")); + DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from " + "ldap\n")); #if 0 /* should we automagically migrate old tdb value here ? */ if (account_policy_get(policy_index, value)) goto update_ldap; - DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying default\n", policy_index)); + DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying " + "default\n", policy_index)); #endif if (!account_policy_get_default(policy_index, value)) { @@ -3520,7 +3645,8 @@ static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, int poli update_cache: if (!cache_account_policy_set(policy_index, *value)) { - DEBUG(0,("ldapsam_get_account_policy: failed to update local tdb as a cache\n")); + DEBUG(0,("ldapsam_get_account_policy: failed to update local " + "tdb as a cache\n")); return NT_STATUS_UNSUCCESSFUL; } @@ -3536,39 +3662,44 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, { struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data; - LDAP *ldap_struct = ldap_state->smbldap_state->ldap_struct; LDAPMessage *msg = NULL; LDAPMessage *entry; char *allsids = NULL; - char *tmp; int i, rc, num_mapped; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NTSTATUS result = NT_STATUS_NO_MEMORY; + TALLOC_CTX *mem_ctx; + LDAP *ld; + BOOL is_builtin; - if (!lp_parm_bool(-1, "ldapsam", "trusted", False)) - return pdb_default_lookup_rids(methods, domain_sid, - num_rids, rids, names, attrs); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + goto done; + } - if (!sid_equal(domain_sid, get_global_sam_sid())) { - /* TODO: Sooner or later we need to look up BUILTIN rids as - * well. -- vl */ + if (!sid_check_is_builtin(domain_sid) && + !sid_check_is_domain(domain_sid)) { + result = NT_STATUS_INVALID_PARAMETER; goto done; } for (i=0; ismbldap_state, lp_ldap_user_suffix(), LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0, &msg); - - SAFE_FREE(filter); + talloc_autofree_ldapmsg(mem_ctx, msg); } if (rc != LDAP_SUCCESS) goto done; + ld = ldap_state->smbldap_state->ldap_struct; num_mapped = 0; - for (entry = ldap_first_entry(ldap_struct, msg); + for (entry = ldap_first_entry(ld, msg); entry != NULL; - entry = ldap_next_entry(ldap_struct, entry)) - { + entry = ldap_next_entry(ld, entry)) { uint32 rid; int rid_index; - fstring str; + const char *name; - if (!ldapsam_extract_rid_from_entry(ldap_struct, entry, - get_global_sam_sid(), + if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid, &rid)) { DEBUG(2, ("Could not find sid from ldap entry\n")); continue; } - if (!smbldap_get_single_attribute(ldap_struct, entry, - "uid", str, sizeof(str)-1)) { + name = smbldap_talloc_single_attribute(ld, entry, "uid", + names); + if (name == NULL) { DEBUG(2, ("Could not retrieve uid attribute\n")); continue; } @@ -3626,9 +3760,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, } attrs[rid_index] = SID_NAME_USER; - names[rid_index] = talloc_strdup(names, str); - if (names[rid_index] == NULL) return NT_STATUS_NO_MEMORY; - + names[rid_index] = name; num_mapped += 1; } @@ -3638,49 +3770,83 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, goto done; } - if (msg != NULL) { - ldap_msgfree(msg); - } - /* Same game for groups */ { char *filter; - const char *ldap_attrs[] = { "cn", "sambaSid", NULL }; + const char *ldap_attrs[] = { "cn", "displayName", "sambaSid", + "sambaGroupType", NULL }; - asprintf(&filter, ("(&(objectClass=sambaGroupMapping)(|%s))"), - allsids); - if (filter == NULL) return NT_STATUS_NO_MEMORY; + filter = talloc_asprintf( + mem_ctx, "(&(objectClass=sambaGroupMapping)(|%s))", + allsids); + if (filter == NULL) { + goto done; + } rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(), LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0, &msg); - - SAFE_FREE(filter); + talloc_autofree_ldapmsg(mem_ctx, msg); } if (rc != LDAP_SUCCESS) goto done; - for (entry = ldap_first_entry(ldap_struct, msg); + /* ldap_struct might have changed due to a reconnect */ + + ld = ldap_state->smbldap_state->ldap_struct; + + /* For consistency checks, we already checked we're only domain or builtin */ + + is_builtin = sid_check_is_builtin(domain_sid); + + for (entry = ldap_first_entry(ld, msg); entry != NULL; - entry = ldap_next_entry(ldap_struct, entry)) + entry = ldap_next_entry(ld, entry)) { uint32 rid; int rid_index; - fstring str; + const char *attr; + enum SID_NAME_USE type; + const char *dn = smbldap_talloc_dn(mem_ctx, ld, entry); + + attr = smbldap_talloc_single_attribute(ld, entry, "sambaGroupType", + mem_ctx); + if (attr == NULL) { + DEBUG(2, ("Could not extract type from ldap entry %s\n", + dn)); + continue; + } - if (!ldapsam_extract_rid_from_entry(ldap_struct, entry, - get_global_sam_sid(), + type = atol(attr); + + /* Consistency checks */ + if ((is_builtin && (type != SID_NAME_WKN_GRP)) || + (!is_builtin && ((type != SID_NAME_ALIAS) && + (type != SID_NAME_DOM_GRP)))) { + DEBUG(2, ("Rejecting invalid group mapping entry %s\n", dn)); + } + + if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid, &rid)) { - DEBUG(2, ("Could not find sid from ldap entry\n")); + DEBUG(2, ("Could not find sid from ldap entry %s\n", dn)); continue; } - if (!smbldap_get_single_attribute(ldap_struct, entry, - "cn", str, sizeof(str)-1)) { - DEBUG(2, ("Could not retrieve cn attribute\n")); + attr = smbldap_talloc_single_attribute(ld, entry, "cn", names); + + if (attr == NULL) { + DEBUG(10, ("Could not retrieve 'cn' attribute from %s\n", + dn)); + attr = smbldap_talloc_single_attribute( + ld, entry, "displayName", names); + } + + if (attr == NULL) { + DEBUG(2, ("Could not retrieve naming attribute from %s\n", + dn)); continue; } @@ -3694,9 +3860,8 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, continue; } - attrs[rid_index] = SID_NAME_DOM_GRP; - names[rid_index] = talloc_strdup(names, str); - if (names[rid_index] == NULL) return NT_STATUS_NO_MEMORY; + attrs[rid_index] = type; + names[rid_index] = attr; num_mapped += 1; } @@ -3706,11 +3871,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, result = (num_mapped == num_rids) ? NT_STATUS_OK : STATUS_SOME_UNMAPPED; done: - SAFE_FREE(allsids); - - if (msg != NULL) - ldap_msgfree(msg); - + talloc_free(mem_ctx); return result; } @@ -3833,7 +3994,6 @@ static BOOL ldapsam_search_firstpage(struct pdb_search *search) static BOOL ldapsam_search_nextpage(struct pdb_search *search) { struct ldap_search_state *state = search->private_data; - LDAP *ld = state->connection->ldap_struct; int rc; if (!state->connection->paged_results) { @@ -3850,7 +4010,7 @@ static BOOL ldapsam_search_nextpage(struct pdb_search *search) if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) return False; - state->current_entry = ldap_first_entry(ld, state->entries); + state->current_entry = ldap_first_entry(state->connection->ldap_struct, state->entries); if (state->current_entry == NULL) { ldap_msgfree(state->entries); @@ -3864,7 +4024,6 @@ static BOOL ldapsam_search_next_entry(struct pdb_search *search, struct samr_displayentry *entry) { struct ldap_search_state *state = search->private_data; - LDAP *ld = state->connection->ldap_struct; BOOL result; retry: @@ -3875,17 +4034,17 @@ static BOOL ldapsam_search_next_entry(struct pdb_search *search, !ldapsam_search_nextpage(search)) return False; - result = state->ldap2displayentry(state, search->mem_ctx, ld, + result = state->ldap2displayentry(state, search->mem_ctx, state->connection->ldap_struct, state->current_entry, entry); if (!result) { char *dn; - dn = ldap_get_dn(ld, state->current_entry); + dn = ldap_get_dn(state->connection->ldap_struct, state->current_entry); DEBUG(5, ("Skipping entry %s\n", dn != NULL ? dn : "")); if (dn != NULL) ldap_memfree(dn); } - state->current_entry = ldap_next_entry(ld, state->current_entry); + state->current_entry = ldap_next_entry(state->connection->ldap_struct, state->current_entry); if (state->current_entry == NULL) { ldap_msgfree(state->entries); @@ -4002,7 +4161,8 @@ static BOOL ldapuser2displayentry(struct ldap_search_state *state, ldap_value_free(vals); if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { - DEBUG(0, ("sid %s does not belong to our domain\n", sid_string_static(&sid))); + DEBUG(0, ("sid %s does not belong to our domain\n", + sid_string_static(&sid))); return False; } @@ -4102,10 +4262,14 @@ static BOOL ldapgroup2displayentry(struct ldap_search_state *state, DEBUG(5, ("\"cn\" not found\n")); return False; } - pull_utf8_talloc(mem_ctx, CONST_DISCARD(char **, &result->account_name), vals[0]); + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); } else { - pull_utf8_talloc(mem_ctx, CONST_DISCARD(char **, &result->account_name), vals[0]); + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); } ldap_value_free(vals); @@ -4146,17 +4310,21 @@ static BOOL ldapgroup2displayentry(struct ldap_search_state *state, case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: - if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { - DEBUG(0, ("%s is not in our domain\n", sid_string_static(&sid))); + if (!sid_peek_check_rid(get_global_sam_sid(), &sid, + &result->rid)) { + DEBUG(0, ("%s is not in our domain\n", + sid_string_static(&sid))); return False; } break; case SID_NAME_WKN_GRP: - if (!sid_peek_check_rid(&global_sid_Builtin, &sid, &result->rid)) { + if (!sid_peek_check_rid(&global_sid_Builtin, &sid, + &result->rid)) { - DEBUG(0, ("%s is not in builtin sid\n", sid_string_static(&sid))); + DEBUG(0, ("%s is not in builtin sid\n", + sid_string_static(&sid))); return False; } break; @@ -4191,7 +4359,8 @@ static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, "(&(objectclass=sambaGroupMapping)" "(sambaGroupType=%d))", type); state->attrs = talloc_attrs(search->mem_ctx, "cn", "sambaSid", - "displayName", "description", "sambaGroupType", NULL); + "displayName", "description", + "sambaGroupType", NULL); state->attrsonly = 0; state->pagedresults_cookie = NULL; state->entries = NULL; @@ -4232,6 +4401,214 @@ static BOOL ldapsam_search_aliases(struct pdb_methods *methods, return False; } +static BOOL ldapsam_rid_algorithm(struct pdb_methods *methods) +{ + return False; +} + +static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv, + uint32 *rid) +{ + struct smbldap_state *smbldap_state = priv->smbldap_state; + + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + LDAPMod **mods = NULL; + NTSTATUS status; + char *value; + int rc; + uint32 nextRid = 0; + + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } + + status = smbldap_search_domain_info(smbldap_state, &result, + get_global_sam_name(), False); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not get domain info: %s\n", + nt_errstr(status))); + goto done; + } + + talloc_autofree_ldapmsg(mem_ctx, result); + + entry = ldap_first_entry(priv2ld(priv), result); + if (entry == NULL) { + DEBUG(0, ("Could not get domain info entry\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + /* Find the largest of the three attributes "sambaNextRid", + "sambaNextGroupRid" and "sambaNextUserRid". I gave up on the + concept of differentiating between user and group rids, and will + use only "sambaNextRid" in the future. But for compatibility + reasons I look if others have chosen different strategies -- VL */ + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextUserRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaNextGroupRid", mem_ctx); + if (value != NULL) { + uint32 tmp = (uint32)strtoul(value, NULL, 10); + nextRid = MAX(nextRid, tmp); + } + + if (nextRid == 0) { + nextRid = BASE_RID-1; + } + + nextRid += 1; + + smbldap_make_mod(priv2ld(priv), entry, &mods, "sambaNextRid", + talloc_asprintf(mem_ctx, "%d", nextRid)); + talloc_autofree_ldapmod(mem_ctx, mods); + + rc = smbldap_modify(smbldap_state, + smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry), + mods); + + /* ACCESS_DENIED is used as a placeholder for "the modify failed, + * please retry" */ + + status = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + + done: + if (NT_STATUS_IS_OK(status)) { + *rid = nextRid; + } + + talloc_free(mem_ctx); + return status; +} + +static BOOL ldapsam_new_rid(struct pdb_methods *methods, uint32 *rid) +{ + int i; + + for (i=0; i<10; i++) { + NTSTATUS result = ldapsam_get_new_rid(methods->private_data, + rid); + if (NT_STATUS_IS_OK(result)) { + return True; + } + + if (!NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) { + return False; + } + + /* The ldap update failed (maybe a race condition), retry */ + } + + /* Tried 10 times, fail. */ + return False; +} + +static BOOL ldapsam_sid_to_id(struct pdb_methods *methods, + const DOM_SID *sid, + union unid_t *id, enum SID_NAME_USE *type) +{ + struct ldapsam_privates *priv = methods->private_data; + char *filter; + const char *attrs[] = { "sambaGroupType", "gidNumber", "uidNumber", + NULL }; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + BOOL ret = False; + char *value; + int rc; + + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + filter = talloc_asprintf(mem_ctx, + "(&(sambaSid=%s)" + "(|(objectClass=sambaGroupMapping)" + "(objectClass=sambaSamAccount)))", + sid_string_static(sid)); + if (filter == NULL) { + DEBUG(5, ("talloc_asprintf failed\n")); + goto done; + } + + rc = smbldap_search_suffix(priv->smbldap_state, filter, + attrs, &result); + if (rc != LDAP_SUCCESS) { + goto done; + } + talloc_autofree_ldapmsg(mem_ctx, result); + + if (ldap_count_entries(priv2ld(priv), result) != 1) { + DEBUG(10, ("Got %d entries, expected one\n", + ldap_count_entries(priv2ld(priv), result))); + goto done; + } + + entry = ldap_first_entry(priv2ld(priv), result); + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "sambaGroupType", mem_ctx); + + if (value != NULL) { + const char *gid_str; + /* It's a group */ + + gid_str = smbldap_talloc_single_attribute( + priv2ld(priv), entry, "gidNumber", mem_ctx); + if (gid_str == NULL) { + DEBUG(1, ("%s has sambaGroupType but no gidNumber\n", + smbldap_talloc_dn(mem_ctx, priv2ld(priv), + entry))); + goto done; + } + + id->gid = strtoul(gid_str, NULL, 10); + *type = strtoul(value, NULL, 10); + ret = True; + goto done; + } + + /* It must be a user */ + + value = smbldap_talloc_single_attribute(priv2ld(priv), entry, + "uidNumber", mem_ctx); + if (value == NULL) { + DEBUG(1, ("Could not find uidNumber in %s\n", + smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry))); + goto done; + } + + id->uid = strtoul(value, NULL, 10); + *type = SID_NAME_USER; + + ret = True; + done: + talloc_free(mem_ctx); + return ret; +} + /********************************************************************** Housekeeping *********************************************************************/ @@ -4288,15 +4665,15 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS ** (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry; (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry; (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping; - (*pdb_method)->enum_group_members = ldapsam_enum_group_members; - (*pdb_method)->enum_group_memberships = ldapsam_enum_group_memberships; - (*pdb_method)->lookup_rids = ldapsam_lookup_rids; (*pdb_method)->get_account_policy = ldapsam_get_account_policy; (*pdb_method)->set_account_policy = ldapsam_set_account_policy; (*pdb_method)->get_seq_num = ldapsam_get_seq_num; + (*pdb_method)->rid_algorithm = ldapsam_rid_algorithm; + (*pdb_method)->new_rid = ldapsam_new_rid; + /* TODO: Setup private data and free */ ldap_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct ldapsam_privates); @@ -4377,7 +4754,8 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co pstring domain_sid_string; char *dn; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) { + nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -4391,27 +4769,41 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co (*pdb_method)->search_groups = ldapsam_search_groups; (*pdb_method)->search_aliases = ldapsam_search_aliases; + if (lp_parm_bool(-1, "ldapsam", "trusted", False)) { + (*pdb_method)->enum_group_members = ldapsam_enum_group_members; + (*pdb_method)->enum_group_memberships = + ldapsam_enum_group_memberships; + (*pdb_method)->lookup_rids = ldapsam_lookup_rids; + (*pdb_method)->sid_to_id = ldapsam_sid_to_id; + } + ldap_state = (*pdb_method)->private_data; ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT; /* Try to setup the Domain Name, Domain SID, algorithmic rid base */ - nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, &result, + nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, + &result, ldap_state->domain_name, True); if ( !NT_STATUS_IS_OK(nt_status) ) { - DEBUG(2, ("pdb_init_ldapsam: WARNING: Could not get domain info, nor add one to the domain\n")); - DEBUGADD(2, ("pdb_init_ldapsam: Continuing on regardless, will be unable to allocate new users/groups, \ -and will risk BDCs having inconsistant SIDs\n")); + DEBUG(2, ("pdb_init_ldapsam: WARNING: Could not get domain " + "info, nor add one to the domain\n")); + DEBUGADD(2, ("pdb_init_ldapsam: Continuing on regardless, " + "will be unable to allocate new users/groups, " + "and will risk BDCs having inconsistant SIDs\n")); sid_copy(&ldap_state->domain_sid, get_global_sam_sid()); return NT_STATUS_OK; } - /* Given that the above might fail, everything below this must be optional */ + /* Given that the above might fail, everything below this must be + * optional */ - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, + result); if (!entry) { - DEBUG(0, ("pdb_init_ldapsam: Could not get domain info entry\n")); + DEBUG(0, ("pdb_init_ldapsam: Could not get domain info " + "entry\n")); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -4424,35 +4816,51 @@ and will risk BDCs having inconsistant SIDs\n")); ldap_state->domain_dn = smb_xstrdup(dn); ldap_memfree(dn); - if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), - domain_sid_string)) { + if (smbldap_get_single_pstring( + ldap_state->smbldap_state->ldap_struct, + entry, + get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_USER_SID), + domain_sid_string)) { BOOL found_sid; if (!string_to_sid(&ldap_domain_sid, domain_sid_string)) { - DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be read as a valid SID\n", domain_sid_string)); + DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be " + "read as a valid SID\n", domain_sid_string)); return NT_STATUS_INVALID_PARAMETER; } - found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, &secrets_domain_sid); - if (!found_sid || !sid_equal(&secrets_domain_sid, &ldap_domain_sid)) { + found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, + &secrets_domain_sid); + if (!found_sid || !sid_equal(&secrets_domain_sid, + &ldap_domain_sid)) { fstring new_sid_str, old_sid_str; - DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain %s based on pdb_ldap results %s -> %s\n", - ldap_state->domain_name, - sid_to_string(old_sid_str, &secrets_domain_sid), - sid_to_string(new_sid_str, &ldap_domain_sid))); + DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain " + "%s based on pdb_ldap results %s -> %s\n", + ldap_state->domain_name, + sid_to_string(old_sid_str, + &secrets_domain_sid), + sid_to_string(new_sid_str, + &ldap_domain_sid))); /* reset secrets.tdb sid */ - secrets_store_domain_sid(ldap_state->domain_name, &ldap_domain_sid); - DEBUG(1, ("New global sam SID: %s\n", sid_to_string(new_sid_str, get_global_sam_sid()))); + secrets_store_domain_sid(ldap_state->domain_name, + &ldap_domain_sid); + DEBUG(1, ("New global sam SID: %s\n", + sid_to_string(new_sid_str, + get_global_sam_sid()))); } sid_copy(&ldap_state->domain_sid, &ldap_domain_sid); } - if (smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string( dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE ), - alg_rid_base_string)) { + if (smbldap_get_single_pstring( + ldap_state->smbldap_state->ldap_struct, + entry, + get_attr_key2string( dominfo_attr_list, + LDAP_ATTR_ALGORITHMIC_RID_BASE ), + alg_rid_base_string)) { alg_rid_base = (uint32)atol(alg_rid_base_string); if (alg_rid_base != algorithmic_rid_base()) { - DEBUG(0, ("The value of 'algorithmic RID base' has changed since the LDAP\n" + DEBUG(0, ("The value of 'algorithmic RID base' has " + "changed since the LDAP\n" "database was initialised. Aborting. \n")); ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; diff --git a/source/passdb/pdb_nds.c b/source/passdb/pdb_nds.c index cf2d1d7c8a8..49c3c9db064 100644 --- a/source/passdb/pdb_nds.c +++ b/source/passdb/pdb_nds.c @@ -771,13 +771,16 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, result = pdb_get_backend_private_data(sam_acct, methods); if (!result) { - attr_list = get_userattr_list(ldap_state->schema_ver); + attr_list = get_userattr_list(NULL, + ldap_state->schema_ver); rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list ); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - pdb_set_backend_private_data(sam_acct, result, private_data_free_fn, methods, PDB_CHANGED); + pdb_set_backend_private_data(sam_acct, result, NULL, + methods, PDB_CHANGED); + talloc_autofree_ldapmsg(sam_acct->mem_ctx, result); } if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { diff --git a/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c index 487df96e953..06a3f4f4a13 100644 --- a/source/passdb/pdb_smbpasswd.c +++ b/source/passdb/pdb_smbpasswd.c @@ -594,7 +594,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str size_t new_entry_length; char *new_entry; SMB_OFF_T offpos; - uint32 max_found_uid = 0; /* Open the smbpassword file - for update. */ fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth); @@ -619,11 +618,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); return False; } - - /* Look for a free uid for use in non-unix accounts */ - if (pwd->smb_userid > max_found_uid) { - max_found_uid = pwd->smb_userid; - } } /* Ok - entry doesn't exist. We can add it */ @@ -1161,14 +1155,13 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas /* If the user specified a RID, make sure its able to be both stored and retreived */ if (rid == DOMAIN_USER_RID_GUEST) { - struct passwd *passwd = getpwnam_alloc(lp_guestaccount()); + struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount()); if (!passwd) { DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount())); return False; } smb_pw->smb_userid=passwd->pw_uid; - passwd_free(&passwd); - + talloc_free(passwd); } else if (algorithmic_pdb_rid_is_user(rid)) { smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid); } else { @@ -1204,7 +1197,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, /* verify the user account exists */ - if ( !(pwfile = getpwnam_alloc(pw_buf->smb_name)) ) { + if ( !(pwfile = getpwnam_alloc(NULL, pw_buf->smb_name)) ) { DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid " "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid)); return False; @@ -1213,7 +1206,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) return False; - passwd_free(&pwfile); + talloc_free(pwfile); /* set remaining fields */ @@ -1532,6 +1525,11 @@ done: return (ret); } +static BOOL smbpasswd_rid_algorithm(struct pdb_methods *methods) +{ + return True; +} + static void free_private_data(void **vp) { struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp; @@ -1563,6 +1561,8 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account; (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account; + (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm; + /* Setup private data and free function */ privates = TALLOC_ZERO_P(pdb_context->mem_ctx, struct smbpasswd_privates); diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index 370c8adc7dc..74f47e70dca 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -864,7 +864,98 @@ done: return (ret); } - + +static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods) +{ + return False; +} + +/* + * Historically, winbind was responsible for allocating RIDs, so the next RID + * value was stored in winbindd_idmap.tdb. It has been moved to passdb now, + * but for compatibility reasons we still keep the the next RID counter in + * winbindd_idmap.tdb. + */ + +/***************************************************************************** + Initialise idmap database. For now (Dec 2005) this is a copy of the code in + sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from + winbind completely and store the RID counter in passdb.tdb. + + Dont' fully initialize with the HWM values, if it's new, we're only + interested in the RID counter. +*****************************************************************************/ + +static BOOL init_idmap_tdb(TDB_CONTEXT *tdb) +{ + int32 version; + + if (tdb_lock_bystring(tdb, "IDMAP_VERSION", 0) != 0) { + DEBUG(0, ("Could not lock IDMAP_VERSION\n")); + return False; + } + + version = tdb_fetch_int32(tdb, "IDMAP_VERSION"); + + if (version == -1) { + /* No key found, must be a new db */ + if (tdb_store_int32(tdb, "IDMAP_VERSION", + IDMAP_VERSION) != 0) { + DEBUG(0, ("Could not store IDMAP_VERSION\n")); + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return False; + } + version = IDMAP_VERSION; + } + + if (version != IDMAP_VERSION) { + DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please " + "start winbind once\n", IDMAP_VERSION, version)); + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return False; + } + + tdb_unlock_bystring(tdb, "IDMAP_VERSION"); + return True; +} + +static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid) +{ + TDB_CONTEXT *tdb; + uint32 rid; + BOOL ret = False; + + tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, + TDB_DEFAULT, O_RDWR | O_CREAT, 0644); + + if (tdb == NULL) { + DEBUG(1, ("Could not open idmap: %s\n", strerror(errno))); + goto done; + } + + if (!init_idmap_tdb(tdb)) { + DEBUG(1, ("Could not init idmap\n")); + goto done; + } + + rid = BASE_RID; /* Default if not set */ + + if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) { + DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n")); + goto done; + } + + *prid = rid; + ret = True; + + done: + if ((tdb != NULL) && (tdb_close(tdb) != 0)) { + smb_panic("tdb_close(idmap_tdb) failed\n"); + } + + return ret; +} + static void free_private_data(void **vp) { struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp; @@ -908,6 +999,9 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account; (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account; + (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm; + (*pdb_method)->new_rid = tdbsam_new_rid; + tdb_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct tdbsam_privates); if (!tdb_state) { diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index 88dabbd6443..69bafc7ce57 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -388,10 +388,11 @@ BOOL secrets_store_trust_account_password(const char *domain, uint8 new_pwd[16]) * @return true if succeeded **/ -BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_dom_name, - size_t uni_name_len, const char* pwd, - DOM_SID sid) -{ +BOOL secrets_store_trusted_domain_password(const char* domain, const char* pwd, + const DOM_SID *sid) +{ + smb_ucs2_t *uni_dom_name; + /* packing structures */ pstring pass_buf; int pass_len = 0; @@ -399,13 +400,15 @@ BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_d struct trusted_dom_pass pass; ZERO_STRUCT(pass); - - /* unicode domain name and its length */ - if (!uni_dom_name) + + if (push_ucs2_allocate(&uni_dom_name, domain) < 0) { + DEBUG(0, ("Could not convert domain name %s to unicode\n", + domain)); return False; - + } + strncpy_w(pass.uni_name, uni_dom_name, sizeof(pass.uni_name) - 1); - pass.uni_name_len = uni_name_len; + pass.uni_name_len = strlen_w(uni_dom_name)+1; /* last change time */ pass.mod_time = time(NULL); @@ -415,7 +418,7 @@ BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_d fstrcpy(pass.pass, pwd); /* domain sid */ - sid_copy(&pass.domain_sid, &sid); + sid_copy(&pass.domain_sid, sid); pass_len = tdb_trusted_dom_pass_pack(pass_buf, pass_buf_len, &pass); @@ -658,138 +661,97 @@ BOOL fetch_ldap_pw(char **dn, char** pw) /** * Get trusted domains info from secrets.tdb. - * - * The linked list is allocated on the supplied talloc context, caller gets to destroy - * when done. - * - * @param ctx Allocation context - * @param enum_ctx Starting index, eg. we can start fetching at third - * or sixth trusted domain entry. Zero is the first index. - * Value it is set to is the enum context for the next enumeration. - * @param num_domains Number of domain entries to fetch at one call - * @param domains Pointer to array of trusted domain structs to be filled up - * - * @return nt status code of rpc response **/ -NTSTATUS secrets_get_trusted_domains(TALLOC_CTX* ctx, int* enum_ctx, unsigned int max_num_domains, - int *num_domains, TRUSTDOM ***domains) +NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains, + struct trustdom_info ***domains) { TDB_LIST_NODE *keys, *k; - TRUSTDOM *dom = NULL; char *pattern; - unsigned int start_idx; - uint32 idx = 0; - size_t size = 0, packed_size = 0; - fstring dom_name; - char *packed_pass; - struct trusted_dom_pass *pass = TALLOC_ZERO_P(ctx, struct trusted_dom_pass); - NTSTATUS status; if (!secrets_init()) return NT_STATUS_ACCESS_DENIED; - if (!pass) { - DEBUG(0, ("talloc_zero failed!\n")); - return NT_STATUS_NO_MEMORY; - } - - *num_domains = 0; - start_idx = *enum_ctx; - /* generate searching pattern */ - if (!(pattern = talloc_asprintf(ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS))) { - DEBUG(0, ("secrets_get_trusted_domains: talloc_asprintf() failed!\n")); + pattern = talloc_asprintf(mem_ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS); + if (pattern == NULL) { + DEBUG(0, ("secrets_trusted_domains: talloc_asprintf() " + "failed!\n")); return NT_STATUS_NO_MEMORY; } - DEBUG(5, ("secrets_get_trusted_domains: looking for %d domains, starting at index %d\n", - max_num_domains, *enum_ctx)); - - *domains = TALLOC_ZERO_ARRAY(ctx, TRUSTDOM *, max_num_domains); + *domains = NULL; + *num_domains = 0; /* fetching trusted domains' data and collecting them in a list */ keys = tdb_search_keys(tdb, pattern); - /* - * if there's no keys returned ie. no trusted domain, - * return "no more entries" code - */ - status = NT_STATUS_NO_MORE_ENTRIES; - /* searching for keys in secrets db -- way to go ... */ for (k = keys; k; k = k->next) { + char *packed_pass; + size_t size = 0, packed_size = 0; + struct trusted_dom_pass pass; char *secrets_key; + struct trustdom_info *dom_info; /* important: ensure null-termination of the key string */ - secrets_key = SMB_STRNDUP(k->node_key.dptr, k->node_key.dsize); + secrets_key = talloc_strndup(mem_ctx, + k->node_key.dptr, + k->node_key.dsize); if (!secrets_key) { DEBUG(0, ("strndup failed!\n")); return NT_STATUS_NO_MEMORY; } packed_pass = secrets_fetch(secrets_key, &size); - packed_size = tdb_trusted_dom_pass_unpack(packed_pass, size, pass); + packed_size = tdb_trusted_dom_pass_unpack(packed_pass, size, + &pass); /* packed representation isn't needed anymore */ SAFE_FREE(packed_pass); if (size != packed_size) { - DEBUG(2, ("Secrets record %s is invalid!\n", secrets_key)); + DEBUG(2, ("Secrets record %s is invalid!\n", + secrets_key)); continue; } - - pull_ucs2_fstring(dom_name, pass->uni_name); - DEBUG(18, ("Fetched secret record num %d.\nDomain name: %s, SID: %s\n", - idx, dom_name, sid_string_static(&pass->domain_sid))); - - SAFE_FREE(secrets_key); - - if (idx >= start_idx && idx < start_idx + max_num_domains) { - dom = TALLOC_ZERO_P(ctx, TRUSTDOM); - if (!dom) { - /* free returned tdb record */ - return NT_STATUS_NO_MEMORY; - } - - /* copy domain sid */ - SMB_ASSERT(sizeof(dom->sid) == sizeof(pass->domain_sid)); - memcpy(&(dom->sid), &(pass->domain_sid), sizeof(dom->sid)); - - /* copy unicode domain name */ - dom->name = TALLOC_MEMDUP(ctx, pass->uni_name, - (strlen_w(pass->uni_name) + 1) * sizeof(smb_ucs2_t)); - - (*domains)[idx - start_idx] = dom; - - DEBUG(18, ("Secret record is in required range.\n \ - start_idx = %d, max_num_domains = %d. Added to returned array.\n", - start_idx, max_num_domains)); - *enum_ctx = idx + 1; - (*num_domains)++; - - /* set proper status code to return */ - if (k->next) { - /* there are yet some entries to enumerate */ - status = STATUS_MORE_ENTRIES; - } else { - /* this is the last entry in the whole enumeration */ - status = NT_STATUS_OK; - } - } else { - DEBUG(18, ("Secret is outside the required range.\n \ - start_idx = %d, max_num_domains = %d. Not added to returned array\n", - start_idx, max_num_domains)); + if (pass.domain_sid.num_auths != 4) { + DEBUG(0, ("SID %s is not a domain sid, has %d " + "auths instead of 4\n", + sid_string_static(&pass.domain_sid), + pass.domain_sid.num_auths)); + continue; } - - idx++; + + dom_info = TALLOC_P(mem_ctx, struct trustdom_info); + if (dom_info == NULL) { + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + if (pull_ucs2_talloc(mem_ctx, &dom_info->name, + pass.uni_name) < 0) { + DEBUG(2, ("pull_ucs2_talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + sid_copy(&dom_info->sid, &pass.domain_sid); + + ADD_TO_ARRAY(mem_ctx, struct trustdom_info *, dom_info, + domains, num_domains); + + if (*domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + talloc_steal(*domains, dom_info); } - DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", *num_domains)); + DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", + *num_domains)); /* free the results of searching the keys */ tdb_search_list_free(keys); - return status; + return NT_STATUS_OK; } /******************************************************************************* diff --git a/source/passdb/util_builtin.c b/source/passdb/util_builtin.c index 12a98d24ddb..9c59df1f687 100644 --- a/source/passdb/util_builtin.c +++ b/source/passdb/util_builtin.c @@ -105,6 +105,6 @@ BOOL sid_check_is_in_builtin(const DOM_SID *sid) sid_copy(&dom_sid, sid); sid_split_rid(&dom_sid, &rid); - return sid_equal(&dom_sid, &global_sid_Builtin); + return sid_check_is_builtin(&dom_sid); } diff --git a/source/passdb/util_unixsids.c b/source/passdb/util_unixsids.c new file mode 100644 index 00000000000..ee8cf2d8f02 --- /dev/null +++ b/source/passdb/util_unixsids.c @@ -0,0 +1,94 @@ +/* + Unix SMB/CIFS implementation. + Translate unix-defined names to SIDs and vice versa + Copyright (C) Volker Lendecke 2005 + + 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" + +BOOL sid_check_is_unix_users(const DOM_SID *sid) +{ + return sid_equal(sid, &global_sid_Unix_Users); +} + +BOOL sid_check_is_in_unix_users(const DOM_SID *sid) +{ + DOM_SID dom_sid; + uint32 rid; + + sid_copy(&dom_sid, sid); + sid_split_rid(&dom_sid, &rid); + + return sid_check_is_unix_users(&dom_sid); +} + +const char *unix_users_domain_name(void) +{ + return "Unix User"; +} + +BOOL lookup_unix_user_name(const char *name, DOM_SID *sid) +{ + struct passwd *pwd; + + pwd = getpwnam_alloc(NULL, name); + if (pwd == NULL) { + return False; + } + + sid_copy(sid, &global_sid_Unix_Users); + sid_append_rid(sid, pwd->pw_uid); /* For 64-bit uid's we have enough + * space ... */ + talloc_free(pwd); + return True; +} + +BOOL sid_check_is_unix_groups(const DOM_SID *sid) +{ + return sid_equal(sid, &global_sid_Unix_Groups); +} + +BOOL sid_check_is_in_unix_groups(const DOM_SID *sid) +{ + DOM_SID dom_sid; + uint32 rid; + + sid_copy(&dom_sid, sid); + sid_split_rid(&dom_sid, &rid); + + return sid_check_is_unix_groups(&dom_sid); +} + +const char *unix_groups_domain_name(void) +{ + return "Unix Group"; +} + +BOOL lookup_unix_group_name(const char *name, DOM_SID *sid) +{ + struct group *grp; + + grp = getgrnam(name); + if (grp == NULL) { + return False; + } + + sid_copy(sid, &global_sid_Unix_Groups); + sid_append_rid(sid, grp->gr_gid); /* For 64-bit uid's we have enough + * space ... */ + return True; +} diff --git a/source/passdb/util_wellknown.c b/source/passdb/util_wellknown.c index 8caae3b2a01..be3cf374469 100644 --- a/source/passdb/util_wellknown.c +++ b/source/passdb/util_wellknown.c @@ -70,6 +70,21 @@ static struct sid_name_map_info special_domains[] = { { &global_sid_NT_Authority, "NT Authority", nt_authority_users }, { NULL, NULL, NULL }}; +BOOL sid_check_is_wellknown_domain(const DOM_SID *sid, const char **name) +{ + int i; + + for (i=0; special_domains[i].sid != NULL; i++) { + if (sid_equal(sid, special_domains[i].sid)) { + if (name != NULL) { + *name = special_domains[i].name; + } + return True; + } + } + return False; +} + /************************************************************************** Looks up a known username from one of the known domains. ***************************************************************************/ diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index a91c2a5c70b..e6c6f7d3dc8 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -3140,7 +3140,11 @@ WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action) win_rc = WERR_SERVER_UNAVAILABLE; goto done; } +#ifdef HAVE_KCM + setenv(KRB5_ENV_CCNAME, "KCM:SYSTEM", 1); +#else setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); +#endif SAFE_FREE(ads->auth.password); ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); @@ -3545,7 +3549,7 @@ static void map_to_os2_driver(fstring drivername) return; } - lines = file_lines_load(mapfile, &numlines); + lines = file_lines_load(mapfile, &numlines,0); if (numlines == 0) { DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile)); return; @@ -5326,9 +5330,11 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* see if we need to try the printer admin list */ - if ( access_granted == 0 ) { - if ( user_in_list(uidtoname(user->ut.uid), lp_printer_admin(snum), user->ut.groups, user->ut.ngroups) ) - return True; + if ((access_granted == 0) && + (token_contains_name_in_list(uidtoname(user->ut.uid), NULL, + user->nt_user_token, + lp_printer_admin(snum)))) { + return True; } talloc_destroy(mem_ctx); diff --git a/source/printing/print_generic.c b/source/printing/print_generic.c index b2484d5b433..18fca678600 100644 --- a/source/printing/print_generic.c +++ b/source/printing/print_generic.c @@ -187,7 +187,7 @@ static int generic_queue_get(const char *printer_name, } numlines = 0; - qlines = fd_lines_load(fd, &numlines); + qlines = fd_lines_load(fd, &numlines,0); close(fd); /* turn the lpq output into a series of job structures */ diff --git a/source/python/py_lsa.c b/source/python/py_lsa.c index 4f809520bc3..a4e8254e0d1 100644 --- a/source/python/py_lsa.c +++ b/source/python/py_lsa.c @@ -186,8 +186,8 @@ static PyObject *lsa_lookup_names(PyObject *self, PyObject *args) } ntstatus = rpccli_lsa_lookup_names( - hnd->cli, mem_ctx, &hnd->pol, num_names, names, &sids, - &name_types); + hnd->cli, mem_ctx, &hnd->pol, num_names, names, + NULL, &sids, &name_types); if (!NT_STATUS_IS_OK(ntstatus) && NT_STATUS_V(ntstatus) != 0x107) { PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus)); diff --git a/source/rpc_client/cli_dfs.c b/source/rpc_client/cli_dfs.c index 78df220ac2a..8b94d6ed9d4 100644 --- a/source/rpc_client/cli_dfs.c +++ b/source/rpc_client/cli_dfs.c @@ -1,183 +1,632 @@ -/* - Unix SMB/CIFS implementation. - RPC pipe client - Copyright (C) Tim Potter 2000-2001, - Copyright (C) Jeremy Allison 2005. - - 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. -*/ +/* + * Unix SMB/CIFS implementation. + * client auto-generated by pidl. DO NOT MODIFY! + */ #include "includes.h" -/* Query DFS support */ - -NTSTATUS rpccli_dfs_exist(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - BOOL *dfs_exists) +NTSTATUS rpccli_dfs_GetManagerVersion(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, uint32 *exist_flag) { prs_struct qbuf, rbuf; - DFS_Q_DFS_EXIST q; - DFS_R_DFS_EXIST r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - + NETDFS_Q_DFS_GETMANAGERVERSION q; + NETDFS_R_DFS_GETMANAGERVERSION r; + ZERO_STRUCT(q); ZERO_STRUCT(r); - + /* Marshall data and send request */ - - init_dfs_q_dfs_exist(&q); - - CLI_DO_RPC( cli, mem_ctx, PI_NETDFS, DFS_EXIST, + + if (!init_netdfs_q_dfs_GetManagerVersion(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_GETMANAGERVERSION, q, r, - qbuf, rbuf, - dfs_io_q_dfs_exist, - dfs_io_r_dfs_exist, + qbuf, rbuf, + netdfs_io_q_dfs_GetManagerVersion, + netdfs_io_r_dfs_GetManagerVersion, NT_STATUS_UNSUCCESSFUL); - + + /* Return variables */ + *exist_flag = r.exist_flag; + /* Return result */ - - *dfs_exists = (r.status != 0); - - result = NT_STATUS_OK; - - return result; + return NT_STATUS_OK; } -NTSTATUS rpccli_dfs_add(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - const char *entrypath, const char *servername, - const char *sharename, const char *comment, uint32 flags) +NTSTATUS rpccli_dfs_Add(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *path, const char *server, const char *share, const char *comment, uint32 flags) { prs_struct qbuf, rbuf; - DFS_Q_DFS_ADD q; - DFS_R_DFS_ADD r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - + NETDFS_Q_DFS_ADD q; + NETDFS_R_DFS_ADD r; + ZERO_STRUCT(q); ZERO_STRUCT(r); - + /* Marshall data and send request */ - - init_dfs_q_dfs_add(&q, entrypath, servername, sharename, comment, - flags); - - CLI_DO_RPC( cli, mem_ctx, PI_NETDFS, DFS_ADD, + + if (!init_netdfs_q_dfs_Add(&q, path, server, share, comment, flags)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ADD, q, r, - qbuf, rbuf, - dfs_io_q_dfs_add, - dfs_io_r_dfs_add, + qbuf, rbuf, + netdfs_io_q_dfs_Add, + netdfs_io_r_dfs_Add, NT_STATUS_UNSUCCESSFUL); - + + /* Return variables */ + /* Return result */ - - result = werror_to_ntstatus(r.status); - - return result; + return werror_to_ntstatus(r.status); } -NTSTATUS rpccli_dfs_remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - const char *entrypath, const char *servername, - const char *sharename) +NTSTATUS rpccli_dfs_Remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *path, const char *server, const char *share) { prs_struct qbuf, rbuf; - DFS_Q_DFS_REMOVE q; - DFS_R_DFS_REMOVE r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - + NETDFS_Q_DFS_REMOVE q; + NETDFS_R_DFS_REMOVE r; + ZERO_STRUCT(q); ZERO_STRUCT(r); - + /* Marshall data and send request */ - - init_dfs_q_dfs_remove(&q, entrypath, servername, sharename); - - CLI_DO_RPC( cli, mem_ctx, PI_NETDFS, DFS_REMOVE, + + if (!init_netdfs_q_dfs_Remove(&q, path, server, share)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_REMOVE, q, r, - qbuf, rbuf, - dfs_io_q_dfs_remove, - dfs_io_r_dfs_remove, + qbuf, rbuf, + netdfs_io_q_dfs_Remove, + netdfs_io_r_dfs_Remove, NT_STATUS_UNSUCCESSFUL); - + + /* Return variables */ + /* Return result */ + return werror_to_ntstatus(r.status); +} - result = werror_to_ntstatus(r.status); +NTSTATUS rpccli_dfs_SetInfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_SETINFO q; + NETDFS_R_DFS_SETINFO r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_SetInfo(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_SETINFO, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_SetInfo, + netdfs_io_r_dfs_SetInfo, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - return result; +NTSTATUS rpccli_dfs_GetInfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *path, const char *server, const char *share, uint32 level, NETDFS_DFS_INFO_CTR *info) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_GETINFO q; + NETDFS_R_DFS_GETINFO r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_GetInfo(&q, path, server, share, level)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_GETINFO, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_GetInfo, + netdfs_io_r_dfs_GetInfo, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + *info = r.info; + + /* Return result */ + return werror_to_ntstatus(r.status); } -NTSTATUS rpccli_dfs_get_info(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - const char *entrypath, const char *servername, - const char *sharename, uint32 info_level, - DFS_INFO_CTR *ctr) +NTSTATUS rpccli_dfs_Enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, uint32 level, uint32 bufsize, NETDFS_DFS_ENUMSTRUCT *info, uint32 *unknown, uint32 *total) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ENUM q; + NETDFS_R_DFS_ENUM r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_Enum(&q, level, bufsize, info, unknown, total)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ENUM, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_Enum, + netdfs_io_r_dfs_Enum, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + *info = r.info; + *total = r.total; + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_Rename(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) { prs_struct qbuf, rbuf; - DFS_Q_DFS_GET_INFO q; - DFS_R_DFS_GET_INFO r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NETDFS_Q_DFS_RENAME q; + NETDFS_R_DFS_RENAME r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_Rename(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_RENAME, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_Rename, + netdfs_io_r_dfs_Rename, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_Move(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_MOVE q; + NETDFS_R_DFS_MOVE r; + ZERO_STRUCT(q); ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_Move(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_MOVE, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_Move, + netdfs_io_r_dfs_Move, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_ManagerGetConfigInfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_MANAGERGETCONFIGINFO q; + NETDFS_R_DFS_MANAGERGETCONFIGINFO r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_ManagerGetConfigInfo(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_MANAGERGETCONFIGINFO, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_ManagerGetConfigInfo, + netdfs_io_r_dfs_ManagerGetConfigInfo, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - init_dfs_q_dfs_get_info(&q, entrypath, servername, sharename, - info_level); +NTSTATUS rpccli_dfs_ManagerSendSiteInfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_MANAGERSENDSITEINFO q; + NETDFS_R_DFS_MANAGERSENDSITEINFO r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_ManagerSendSiteInfo(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_MANAGERSENDSITEINFO, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_ManagerSendSiteInfo, + netdfs_io_r_dfs_ManagerSendSiteInfo, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - CLI_DO_RPC( cli, mem_ctx, PI_NETDFS, DFS_GET_INFO, +NTSTATUS rpccli_dfs_AddFtRoot(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ADDFTROOT q; + NETDFS_R_DFS_ADDFTROOT r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_AddFtRoot(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ADDFTROOT, q, r, - qbuf, rbuf, - dfs_io_q_dfs_get_info, - dfs_io_r_dfs_get_info, + qbuf, rbuf, + netdfs_io_q_dfs_AddFtRoot, + netdfs_io_r_dfs_AddFtRoot, NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_RemoveFtRoot(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_REMOVEFTROOT q; + NETDFS_R_DFS_REMOVEFTROOT r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_RemoveFtRoot(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_REMOVEFTROOT, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_RemoveFtRoot, + netdfs_io_r_dfs_RemoveFtRoot, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + /* Return result */ + return werror_to_ntstatus(r.status); +} - result = werror_to_ntstatus(r.status); - *ctr = r.ctr; +NTSTATUS rpccli_dfs_AddStdRoot(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ADDSTDROOT q; + NETDFS_R_DFS_ADDSTDROOT r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); - return result; + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_AddStdRoot(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ADDSTDROOT, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_AddStdRoot, + netdfs_io_r_dfs_AddStdRoot, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); } -/* Enumerate dfs shares */ +NTSTATUS rpccli_dfs_RemoveStdRoot(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_REMOVESTDROOT q; + NETDFS_R_DFS_REMOVESTDROOT r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_RemoveStdRoot(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_REMOVESTDROOT, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_RemoveStdRoot, + netdfs_io_r_dfs_RemoveStdRoot, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} -NTSTATUS rpccli_dfs_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - uint32 info_level, DFS_INFO_CTR *ctr) +NTSTATUS rpccli_dfs_ManagerInitialize(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) { prs_struct qbuf, rbuf; - DFS_Q_DFS_ENUM q; - DFS_R_DFS_ENUM r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NETDFS_Q_DFS_MANAGERINITIALIZE q; + NETDFS_R_DFS_MANAGERINITIALIZE r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_ManagerInitialize(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_MANAGERINITIALIZE, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_ManagerInitialize, + netdfs_io_r_dfs_ManagerInitialize, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_AddStdRootForced(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ADDSTDROOTFORCED q; + NETDFS_R_DFS_ADDSTDROOTFORCED r; + ZERO_STRUCT(q); ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_AddStdRootForced(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ADDSTDROOTFORCED, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_AddStdRootForced, + netdfs_io_r_dfs_AddStdRootForced, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_GetDcAddress(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_GETDCADDRESS q; + NETDFS_R_DFS_GETDCADDRESS r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_GetDcAddress(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_GETDCADDRESS, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_GetDcAddress, + netdfs_io_r_dfs_GetDcAddress, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - init_dfs_q_dfs_enum(&q, info_level, ctr); +NTSTATUS rpccli_dfs_SetDcAddress(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_SETDCADDRESS q; + NETDFS_R_DFS_SETDCADDRESS r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_SetDcAddress(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_SETDCADDRESS, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_SetDcAddress, + netdfs_io_r_dfs_SetDcAddress, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - r.ctr = ctr; +NTSTATUS rpccli_dfs_FlushFtTable(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_FLUSHFTTABLE q; + NETDFS_R_DFS_FLUSHFTTABLE r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_FlushFtTable(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_FLUSHFTTABLE, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_FlushFtTable, + netdfs_io_r_dfs_FlushFtTable, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - CLI_DO_RPC( cli, mem_ctx, PI_NETDFS, DFS_ENUM, +NTSTATUS rpccli_dfs_Add2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ADD2 q; + NETDFS_R_DFS_ADD2 r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_Add2(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ADD2, q, r, - qbuf, rbuf, - dfs_io_q_dfs_enum, - dfs_io_r_dfs_enum, + qbuf, rbuf, + netdfs_io_q_dfs_Add2, + netdfs_io_r_dfs_Add2, NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} +NTSTATUS rpccli_dfs_Remove2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_REMOVE2 q; + NETDFS_R_DFS_REMOVE2 r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_Remove2(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_REMOVE2, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_Remove2, + netdfs_io_r_dfs_Remove2, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + /* Return result */ + return werror_to_ntstatus(r.status); +} - result = werror_to_ntstatus(r.status); +NTSTATUS rpccli_dfs_EnumEx(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_ENUMEX q; + NETDFS_R_DFS_ENUMEX r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_EnumEx(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_ENUMEX, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_EnumEx, + netdfs_io_r_dfs_EnumEx, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); +} - return result; +NTSTATUS rpccli_dfs_SetInfo2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx) +{ + prs_struct qbuf, rbuf; + NETDFS_Q_DFS_SETINFO2 q; + NETDFS_R_DFS_SETINFO2 r; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + if (!init_netdfs_q_dfs_SetInfo2(&q)) + return NT_STATUS_INVALID_PARAMETER; + + CLI_DO_RPC(cli, mem_ctx, PI_NETDFS, DFS_SETINFO2, + q, r, + qbuf, rbuf, + netdfs_io_q_dfs_SetInfo2, + netdfs_io_r_dfs_SetInfo2, + NT_STATUS_UNSUCCESSFUL); + + /* Return variables */ + + /* Return result */ + return werror_to_ntstatus(r.status); } + diff --git a/source/rpc_client/cli_lsarpc.c b/source/rpc_client/cli_lsarpc.c index aa1cb95fda1..9331d090931 100644 --- a/source/rpc_client/cli_lsarpc.c +++ b/source/rpc_client/cli_lsarpc.c @@ -277,7 +277,9 @@ NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli, NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, POLICY_HND *pol, int num_names, - const char **names, DOM_SID **sids, + const char **names, + const char ***dom_names, + DOM_SID **sids, uint32 **types) { prs_struct qbuf, rbuf; @@ -331,6 +333,15 @@ NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli, goto done; } + if (dom_names != NULL) { + *dom_names = TALLOC_ARRAY(mem_ctx, const char *, num_names); + if (*dom_names == NULL) { + DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + } + for (i = 0; i < num_names; i++) { DOM_RID2 *t_rids = r.dom_rid; uint32 dom_idx = t_rids[i].rid_idx; @@ -339,19 +350,27 @@ NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli, /* Translate optimised sid through domain index array */ - if (dom_idx != 0xffffffff) { + if (dom_idx == 0xffffffff) { + /* Nothing to do, this is unknown */ + ZERO_STRUCTP(sid); + (*types)[i] = SID_NAME_UNKNOWN; + continue; + } - sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid); + sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid); - if (dom_rid != 0xffffffff) { - sid_append_rid(sid, dom_rid); - } + if (dom_rid != 0xffffffff) { + sid_append_rid(sid, dom_rid); + } - (*types)[i] = t_rids[i].type; - } else { - ZERO_STRUCTP(sid); - (*types)[i] = SID_NAME_UNKNOWN; + (*types)[i] = t_rids[i].type; + + if (dom_names == NULL) { + continue; } + + (*dom_names)[i] = rpcstr_pull_unistr2_talloc( + *dom_names, &ref.ref_dom[dom_idx].uni_dom_name); } done: @@ -1298,6 +1317,42 @@ done: return result; } +NTSTATUS rpccli_lsa_open_trusted_domain_by_name(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *pol, const char *name, uint32 access_mask, + POLICY_HND *trustdom_pol) +{ + prs_struct qbuf, rbuf; + LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME q; + LSA_R_OPEN_TRUSTED_DOMAIN_BY_NAME r; + NTSTATUS result; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Initialise input parameters */ + + init_lsa_q_open_trusted_domain_by_name(&q, pol, name, access_mask); + + /* Marshall data and send request */ + + CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_OPENTRUSTDOMBYNAME, + q, r, + qbuf, rbuf, + lsa_io_q_open_trusted_domain_by_name, + lsa_io_r_open_trusted_domain_by_name, + NT_STATUS_UNSUCCESSFUL); + + /* Return output parameters */ + + result = r.status; + + if (NT_STATUS_IS_OK(result)) { + *trustdom_pol = r.handle; + } + + return result; +} + NTSTATUS rpccli_lsa_query_trusted_domain_info_by_sid(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, POLICY_HND *pol, @@ -1372,3 +1427,39 @@ done: return result; } + +NTSTATUS cli_lsa_query_domain_info_policy(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *pol, + uint16 info_class, LSA_DOM_INFO_UNION **info) +{ + prs_struct qbuf, rbuf; + LSA_Q_QUERY_DOM_INFO_POLICY q; + LSA_R_QUERY_DOM_INFO_POLICY r; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Marshall data and send request */ + + init_q_query_dom_info(&q, pol, info_class); + + CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYDOMINFOPOL, + q, r, + qbuf, rbuf, + lsa_io_q_query_dom_info, + lsa_io_r_query_dom_info, + NT_STATUS_UNSUCCESSFUL); + + result = r.status; + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + *info = r.info; + +done: + return result; +} + diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c index b5addf33751..3dc26f61c93 100644 --- a/source/rpc_client/cli_netlogon.c +++ b/source/rpc_client/cli_netlogon.c @@ -468,8 +468,8 @@ WERROR rpccli_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, if (dc_unc != NULL) { char *tmp; - if (rpcstr_pull_unistr2_talloc(mem_ctx, &tmp, - &r.uni_dc_unc) < 0) { + tmp = rpcstr_pull_unistr2_talloc(mem_ctx, &r.uni_dc_unc); + if (tmp == NULL) { return WERR_GENERAL_FAILURE; } if (*tmp == '\\') tmp += 1; @@ -485,8 +485,8 @@ WERROR rpccli_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, if (dc_address != NULL) { char *tmp; - if (rpcstr_pull_unistr2_talloc(mem_ctx, &tmp, - &r.uni_dc_address) < 0) { + tmp = rpcstr_pull_unistr2_talloc(mem_ctx, &r.uni_dc_address); + if (tmp == NULL) { return WERR_GENERAL_FAILURE; } if (*tmp == '\\') tmp += 1; @@ -509,14 +509,14 @@ WERROR rpccli_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, } if ((domain_name_out != NULL) && - (rpcstr_pull_unistr2_talloc(mem_ctx, domain_name_out, - &r.uni_domain_name) < 1)) { + ((*domain_name_out = rpcstr_pull_unistr2_talloc( + mem_ctx, &r.uni_domain_name)) == NULL)) { return WERR_GENERAL_FAILURE; } if ((forest_name != NULL) && - (rpcstr_pull_unistr2_talloc(mem_ctx, forest_name, - &r.uni_forest_name) < 1)) { + ((*forest_name = rpcstr_pull_unistr2_talloc( + mem_ctx, &r.uni_forest_name)) == NULL)) { return WERR_GENERAL_FAILURE; } @@ -525,14 +525,14 @@ WERROR rpccli_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, } if ((dc_site_name != NULL) && - (rpcstr_pull_unistr2_talloc(mem_ctx, dc_site_name, - &r.uni_dc_site_name) < 1)) { + ((*dc_site_name = rpcstr_pull_unistr2_talloc( + mem_ctx, &r.uni_dc_site_name)) == NULL)) { return WERR_GENERAL_FAILURE; } if ((client_site_name != NULL) && - (rpcstr_pull_unistr2_talloc(mem_ctx, client_site_name, - &r.uni_client_site_name) < 1)) { + ((*client_site_name = rpcstr_pull_unistr2_talloc( + mem_ctx, &r.uni_client_site_name)) == NULL)) { return WERR_GENERAL_FAILURE; } @@ -571,8 +571,8 @@ WERROR rpccli_netlogon_dsr_getsitename(struct rpc_pipe_client *cli, } if ((site_name != NULL) && - (rpcstr_pull_unistr2_talloc(mem_ctx, site_name, - &r.uni_site_name) < 1)) { + ((*site_name = rpcstr_pull_unistr2_talloc( + mem_ctx, &r.uni_site_name)) == NULL)) { return WERR_GENERAL_FAILURE; } diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index 23c66acf26e..9cc350bef1b 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -927,7 +927,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli, /* Create the ticket for the service principal and return it in a gss-api wrapped blob. */ ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt, - &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED); + &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL); if (ret) { DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s " @@ -2699,7 +2699,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli, /* Only get a new TGT if username/password are given. */ if (username && password) { - int ret = kerberos_kinit_password(username, password, 0, NULL, NULL); + int ret = kerberos_kinit_password(username, password, 0, NULL, NULL, NULL, False, 0); if (ret) { cli_rpc_pipe_close(result); return NULL; @@ -2737,7 +2737,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli, Close an open named pipe over SMB. Free any authentication data. ****************************************************************************/ -void cli_rpc_pipe_close(struct rpc_pipe_client *cli) + void cli_rpc_pipe_close(struct rpc_pipe_client *cli) { if (!cli_close(cli->cli, cli->fnum)) { DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s " diff --git a/source/rpc_client/cli_samr.c b/source/rpc_client/cli_samr.c index fb95da97aef..744d8174a0a 100644 --- a/source/rpc_client/cli_samr.c +++ b/source/rpc_client/cli_samr.c @@ -360,7 +360,8 @@ NTSTATUS rpccli_samr_del_groupmem(struct rpc_pipe_client *cli, TALLOC_CTX *mem_c NTSTATUS rpccli_samr_query_userinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - POLICY_HND *user_pol, uint16 switch_value, + const POLICY_HND *user_pol, + uint16 switch_value, SAM_USERINFO_CTR **ctr) { prs_struct qbuf, rbuf; @@ -1549,7 +1550,7 @@ NTSTATUS rpccli_samr_create_dom_user(struct rpc_pipe_client *cli, TALLOC_CTX *me /* Set userinfo */ NTSTATUS rpccli_samr_set_userinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - POLICY_HND *user_pol, uint16 switch_value, + const POLICY_HND *user_pol, uint16 switch_value, DATA_BLOB *sess_key, SAM_USERINFO_CTR *ctr) { prs_struct qbuf, rbuf; @@ -1600,7 +1601,7 @@ NTSTATUS rpccli_samr_set_userinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_c /* Set userinfo2 */ NTSTATUS rpccli_samr_set_userinfo2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - POLICY_HND *user_pol, uint16 switch_value, + const POLICY_HND *user_pol, uint16 switch_value, DATA_BLOB *sess_key, SAM_USERINFO_CTR *ctr) { prs_struct qbuf, rbuf; diff --git a/source/rpc_parse/parse_dfs.c b/source/rpc_parse/parse_dfs.c index f102e950042..f1d07053025 100644 --- a/source/rpc_parse/parse_dfs.c +++ b/source/rpc_parse/parse_dfs.c @@ -1,24 +1,6 @@ -/* - * Unix SMB/CIFS implementation. - * MSDfs RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-2000, - * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, - * Copyright (C) Shirish Kalele 2000. - * Copyright (C) Jeremy Allison 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. +/* + * Unix SMB/CIFS implementation. + * parser auto-generated by pidl. DO NOT MODIFY! */ #include "includes.h" @@ -26,519 +8,2660 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_PARSE -/******************************************************************* -Make a DFS_Q_DFS_QUERY structure -*******************************************************************/ - -void init_dfs_q_dfs_exist(DFS_Q_DFS_EXIST *q_d) +/* netdfs structures */ +BOOL init_netdfs_dfs_Info0(NETDFS_DFS_INFO0 *v) { - q_d->dummy = 0; + DEBUG(5,("init_netdfs_dfs_Info0\n")); + + return True; } -/************************************************************* - Read/write a DFS_Q_DFS_EXIST structure - dummy... - ************************************************************/ +BOOL netdfs_io_dfs_Info0_p(const char *desc, NETDFS_DFS_INFO0 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info0_p"); + depth++; + return True; +} -BOOL dfs_io_q_dfs_exist(const char *desc, DFS_Q_DFS_EXIST *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info0_d(const char *desc, NETDFS_DFS_INFO0 *v, prs_struct *ps, int depth) { - if(q_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_q_dfs_exist"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info0_d"); + depth++; + return True; +} +BOOL init_netdfs_dfs_Info1(NETDFS_DFS_INFO1 *v, const char *path) +{ + DEBUG(5,("init_netdfs_dfs_Info1\n")); + + if (path) { + v->ptr0_path = 1; + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + } else { + v->ptr0_path = 0; + } + return True; } - -/************************************************************* - Read/write a DFS_R_DFS_EXIST structure - ************************************************************/ -BOOL dfs_io_r_dfs_exist(const char *desc, DFS_R_DFS_EXIST *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info1_p(const char *desc, NETDFS_DFS_INFO1 *v, prs_struct *ps, int depth) { - if(q_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_r_dfs_exist"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info1_p"); depth++; - - if(!prs_align(ps)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; + + + return True; +} - if(!prs_uint32("exist flag", ps, 0, &q_d->status)) +BOOL netdfs_io_dfs_Info1_d(const char *desc, NETDFS_DFS_INFO1 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info1_d"); + depth++; + if (v->ptr0_path) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + } + return True; } - -/******************************************************************* -Make a DFS_Q_DFS_REMOVE structure -*******************************************************************/ -BOOL init_dfs_q_dfs_remove(DFS_Q_DFS_REMOVE *q_d, const char *entrypath, - const char *servername, const char *sharename) +BOOL init_netdfs_dfs_Info2(NETDFS_DFS_INFO2 *v, const char *path, const char *comment, uint32 state, uint32 num_stores) { - DEBUG(5,("init_dfs_q_dfs_remove\n")); - init_unistr2(&q_d->DfsEntryPath, entrypath, UNI_STR_TERMINATE); - init_unistr2(&q_d->ServerName, servername, UNI_STR_TERMINATE); - init_unistr2(&q_d->ShareName, sharename, UNI_STR_TERMINATE); - q_d->ptr_ServerName = q_d->ptr_ShareName = 1; + DEBUG(5,("init_netdfs_dfs_Info2\n")); + + if (path) { + v->ptr0_path = 1; + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + } else { + v->ptr0_path = 0; + } + + if (comment) { + v->ptr0_comment = 1; + init_unistr2(&v->comment, comment, UNI_FLAGS_NONE); + } else { + v->ptr0_comment = 0; + } + + v->state = state; + + v->num_stores = num_stores; + return True; } -/******************************************************************* -Read/write a DFS_Q_DFS_REMOVE structure -*******************************************************************/ - -BOOL dfs_io_q_dfs_remove(const char *desc, DFS_Q_DFS_REMOVE *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info2_p(const char *desc, NETDFS_DFS_INFO2 *v, prs_struct *ps, int depth) { - if(q_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_q_dfs_remove"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info2_p"); depth++; - - if(!prs_align(ps)) - return False; - - if(!smb_io_unistr2("DfsEntryPath",&q_d->DfsEntryPath, 1, ps, depth)) - return False; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_ServerName", ps, depth, &q_d->ptr_ServerName)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - if(q_d->ptr_ServerName) - if (!smb_io_unistr2("ServerName",&q_d->ServerName, q_d->ptr_ServerName, ps, depth)) - return False; - if(!prs_align(ps)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - - if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName)) + + + if (!prs_uint32("state", ps, depth, &v->state)) return False; - if(q_d->ptr_ShareName) - if (!smb_io_unistr2("ShareName",&q_d->ShareName, q_d->ptr_ShareName, ps, depth)) - return False; - if(!prs_align(ps)) + + if (!prs_uint32("num_stores", ps, depth, &v->num_stores)) return False; - + return True; } -/******************************************************************* -Read/write a DFS_R_DFS_REMOVE structure -*******************************************************************/ - -BOOL dfs_io_r_dfs_remove(const char *desc, DFS_R_DFS_REMOVE *r_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info2_d(const char *desc, NETDFS_DFS_INFO2 *v, prs_struct *ps, int depth) { - if(r_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_r_dfs_remove"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info2_d"); depth++; - - if(!prs_werror("status", ps, depth, &r_d->status)) - return False; - + if (v->ptr0_path) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + } + + if (v->ptr0_comment) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("comment", &v->comment, 1, ps, depth)) + return False; + } + + + return True; } -/******************************************************************* -Make a DFS_Q_DFS_ADD structure -*******************************************************************/ - -BOOL init_dfs_q_dfs_add(DFS_Q_DFS_ADD *q_d, const char *entrypath, - const char *servername, const char *sharename, - const char *comment, uint32 flags) +BOOL init_netdfs_dfs_StorageInfo(NETDFS_DFS_STORAGEINFO *v, uint32 state, const char *server, const char *share) { - DEBUG(5,("init_dfs_q_dfs_add\n")); - q_d->ptr_DfsEntryPath = q_d->ptr_ServerName = q_d->ptr_ShareName = 1; - init_unistr2(&q_d->DfsEntryPath, entrypath, UNI_STR_TERMINATE); - init_unistr2(&q_d->ServerName, servername, UNI_STR_TERMINATE); - init_unistr2(&q_d->ShareName, sharename, UNI_STR_TERMINATE); - if(comment != NULL) { - init_unistr2(&q_d->Comment, comment,UNI_STR_TERMINATE); - q_d->ptr_Comment = 1; + DEBUG(5,("init_netdfs_dfs_StorageInfo\n")); + + v->state = state; + + if (server) { + v->ptr0_server = 1; + init_unistr2(&v->server, server, UNI_FLAGS_NONE); } else { - q_d->ptr_Comment = 0; + v->ptr0_server = 0; } - - q_d->Flags = flags; + + if (share) { + v->ptr0_share = 1; + init_unistr2(&v->share, share, UNI_FLAGS_NONE); + } else { + v->ptr0_share = 0; + } + return True; } -/************************************************************ - Read/write a DFS_Q_DFS_ADD structure - ************************************************************/ - -BOOL dfs_io_q_dfs_add(const char *desc, DFS_Q_DFS_ADD *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_StorageInfo_p(const char *desc, NETDFS_DFS_STORAGEINFO *v, prs_struct *ps, int depth) { - if(q_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_q_dfs_add"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_StorageInfo_p"); depth++; - - if(!prs_align(ps)) - return False; - - if(!smb_io_unistr2("DfsEntryPath",&q_d->DfsEntryPath, 1, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - - if(!smb_io_unistr2("ServerName",&q_d->ServerName, 1, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName)) - return False; - if(!smb_io_unistr2("ShareName",&q_d->ShareName, 1, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_Comment", ps, depth, &q_d->ptr_Comment)) + if (!prs_uint32("state", ps, depth, &v->state)) return False; - if(!smb_io_unistr2("",&q_d->Comment, q_d->ptr_Comment , ps, depth)) + + if (!prs_uint32("ptr0_server", ps, depth, &v->ptr0_server)) return False; - if(!prs_align(ps)) + + + if (!prs_uint32("ptr0_share", ps, depth, &v->ptr0_share)) return False; - - if(!prs_uint32("Flags", ps, depth, &q_d->Flags)) - return True; - + + return True; } -/************************************************************ - Read/write a DFS_R_DFS_ADD structure - ************************************************************/ - -BOOL dfs_io_r_dfs_add(const char *desc, DFS_R_DFS_ADD *r_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_StorageInfo_d(const char *desc, NETDFS_DFS_STORAGEINFO *v, prs_struct *ps, int depth) { - if(r_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_r_dfs_add"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_StorageInfo_d"); depth++; - - if(!prs_werror("status", ps, depth, &r_d->status)) - return False; - + + if (v->ptr0_server) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("server", &v->server, 1, ps, depth)) + return False; + } + + if (v->ptr0_share) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("share", &v->share, 1, ps, depth)) + return False; + } + return True; } -BOOL init_dfs_q_dfs_get_info(DFS_Q_DFS_GET_INFO *q_d, const char *entrypath, - const char *servername, const char *sharename, - uint32 info_level) +BOOL init_netdfs_dfs_Info3(NETDFS_DFS_INFO3 *v, const char *path, const char *comment, uint32 state, uint32 num_stores, NETDFS_DFS_STORAGEINFO **stores) { - DEBUG(5,("init_dfs_q2_get_info\n")); - init_unistr2(&q_d->uni_path, entrypath, UNI_STR_TERMINATE); - init_unistr2(&q_d->uni_server, servername, UNI_STR_TERMINATE); - init_unistr2(&q_d->uni_share, sharename, UNI_STR_TERMINATE); - q_d->level = info_level; - q_d->ptr_server = q_d->ptr_share = 1; + DEBUG(5,("init_netdfs_dfs_Info3\n")); + + if (path) { + v->ptr0_path = 1; + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + } else { + v->ptr0_path = 0; + } + + if (comment) { + v->ptr0_comment = 1; + init_unistr2(&v->comment, comment, UNI_FLAGS_NONE); + } else { + v->ptr0_comment = 0; + } + + v->state = state; + + v->num_stores = num_stores; + + if (stores) { + v->ptr0_stores = 1; + v->stores = *stores; + } else { + v->ptr0_stores = 0; + } + return True; } -/************************************************************ - Read/write a DFS_Q_GET_INFO structure - ************************************************************/ - -BOOL dfs_io_q_dfs_get_info(const char *desc, DFS_Q_DFS_GET_INFO* q_i, prs_struct* ps, int depth) +BOOL netdfs_io_dfs_Info3_p(const char *desc, NETDFS_DFS_INFO3 *v, prs_struct *ps, int depth) { - if(q_i == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_q_dfs_get_info"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info3_p"); depth++; - - if(!smb_io_unistr2("",&q_i->uni_path, 1, ps, depth)) - return False; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_server", ps, depth, &q_i->ptr_server)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - - if(q_i->ptr_server) - if (!smb_io_unistr2("",&q_i->uni_server, q_i->ptr_server, ps, depth)) - return False; - if(!prs_align(ps)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - - if(!prs_uint32("ptr_share", ps, depth, &q_i->ptr_share)) + + + if (!prs_uint32("state", ps, depth, &v->state)) return False; - if(q_i->ptr_share) - if(!smb_io_unistr2("", &q_i->uni_share, q_i->ptr_share, ps, depth)) - return False; - if(!prs_align(ps)) + + if (!prs_uint32("num_stores", ps, depth, &v->num_stores)) return False; - - if(!prs_uint32("level", ps, depth, &q_i->level)) + + if (!prs_uint32("ptr0_stores", ps, depth, &v->ptr0_stores)) return False; + + return True; } -/************************************************************ - Read/write a DFS_R_GET_INFO structure - ************************************************************/ - -BOOL dfs_io_r_dfs_get_info(const char *desc, DFS_R_DFS_GET_INFO* r_i, prs_struct* ps, int depth) +BOOL netdfs_io_dfs_Info3_d(const char *desc, NETDFS_DFS_INFO3 *v, prs_struct *ps, int depth) { - if(r_i == NULL) - return False; - - if(!prs_uint32("level", ps, depth, &r_i->level)) - return False; - if(!prs_uint32("ptr_ctr", ps, depth, &r_i->ptr_ctr)) - return False; - - if(!dfs_io_dfs_info_ctr("", &r_i->ctr, 1, r_i->level, ps, depth)) - return False; - if(!prs_werror("status", ps, depth, &r_i->status)) + uint32 i_stores_1; + + if (v == NULL) return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info3_d"); + depth++; + if (v->ptr0_path) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + } + + if (v->ptr0_comment) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("comment", &v->comment, 1, ps, depth)) + return False; + } + + + + if (v->ptr0_stores) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_stores", ps, depth, &v->size_stores)) + return False; + + if (UNMARSHALLING(ps)) { + v->stores = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->stores)*v->num_stores); + } + for (i_stores_1=0; i_stores_1num_stores;i_stores_1++) { + if (!netdfs_io_dfs_StorageInfo_p("stores", &v->stores[i_stores_1], ps, depth)) + return False; + } + for (i_stores_1=0; i_stores_1num_stores;i_stores_1++) { + if (!netdfs_io_dfs_StorageInfo_d("stores", &v->stores[i_stores_1], ps, depth)) + return False; + } + } + return True; } - -/************************************************************ - Make a DFS_Q_DFS_ENUM structure - ************************************************************/ -BOOL init_dfs_q_dfs_enum(DFS_Q_DFS_ENUM *q_d, uint32 level, DFS_INFO_CTR *ctr) + +BOOL init_netdfs_dfs_Info4(NETDFS_DFS_INFO4 *v, const char *path, const char *comment, uint32 state, uint32 timeout, struct uuid guid, uint32 num_stores, NETDFS_DFS_STORAGEINFO **stores) { - q_d->level = level; - q_d->maxpreflen = -1; - q_d->ptr_buffer = 1; - q_d->level2 = level; - - q_d->ptr_num_entries = 1; - q_d->num_entries = 0; - q_d->num_entries2 = 0; - q_d->reshnd.ptr_hnd = 1; - q_d->reshnd.handle = 0; + DEBUG(5,("init_netdfs_dfs_Info4\n")); + + if (path) { + v->ptr0_path = 1; + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + } else { + v->ptr0_path = 0; + } + + if (comment) { + v->ptr0_comment = 1; + init_unistr2(&v->comment, comment, UNI_FLAGS_NONE); + } else { + v->ptr0_comment = 0; + } + + v->state = state; + + v->timeout = timeout; + + + + v->num_stores = num_stores; + + if (stores) { + v->ptr0_stores = 1; + v->stores = *stores; + } else { + v->ptr0_stores = 0; + } + return True; } - -/************************************************************ - Read or write the DFS_Q_DFS_ENUM structure - ************************************************************/ -BOOL dfs_io_q_dfs_enum(const char *desc, DFS_Q_DFS_ENUM *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info4_p(const char *desc, NETDFS_DFS_INFO4 *v, prs_struct *ps, int depth) { - if(q_d == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "dfs_io_q_dfs_enum"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info4_p"); depth++; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("level", ps, depth, &q_d->level)) - return False; - if(!prs_uint32("maxpreflen", ps, depth, &q_d->maxpreflen)) - return False; - if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - if(!prs_uint32("level2", ps, depth, &q_d->level2)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - if(!prs_uint32("level3", ps, depth, &q_d->level2)) + + + if (!prs_uint32("state", ps, depth, &v->state)) return False; - - if(!prs_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries)) + + if (!prs_uint32("timeout", ps, depth, &v->timeout)) return False; - if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries)) + + if (!smb_io_uuid("guid", &v->guid, ps, depth)) return False; - if(!prs_uint32("num_entries2", ps, depth, &q_d->num_entries2)) + + if (!prs_uint32("num_stores", ps, depth, &v->num_stores)) return False; - if(!smb_io_enum_hnd("resume_hnd",&q_d->reshnd, ps, depth)) + + if (!prs_uint32("ptr0_stores", ps, depth, &v->ptr0_stores)) return False; + + return True; } -/************************************************************ - Read/write a DFS_INFO_CTR structure - ************************************************************/ - -BOOL dfs_io_dfs_info_ctr(const char *desc, DFS_INFO_CTR* ctr, uint32 num_entries, uint32 level, prs_struct* ps, int depth) +BOOL netdfs_io_dfs_Info4_d(const char *desc, NETDFS_DFS_INFO4 *v, prs_struct *ps, int depth) { - int i=0; - - switch(level) { - case 1: - depth++; - /* should depend on whether marshalling or unmarshalling! */ - if(UNMARSHALLING(ps)) { - ctr->dfs.info1 = PRS_ALLOC_MEM(ps, DFS_INFO_1, num_entries); - if (!ctr->dfs.info1) - return False; - } - - for(i=0;idfs.info1[i].ptr_entrypath)) - return False; - } - for(i=0;idfs.info1[i].entrypath, ctr->dfs.info1[i].ptr_entrypath, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - } - depth--; - break; - case 2: - depth++; - if(UNMARSHALLING(ps)) { - ctr->dfs.info2 = PRS_ALLOC_MEM(ps, DFS_INFO_2, num_entries); - if (!ctr->dfs.info2) - return False; - } - - for(i=0;idfs.info2[i].ptr_entrypath)) - return False; - if(!prs_uint32("ptr_comment", ps, depth, &ctr->dfs.info2[i].ptr_comment)) - return False; - if(!prs_uint32("state", ps, depth, &ctr->dfs.info2[i].state)) - return False; - if(!prs_uint32("num_storages", ps, depth, &ctr->dfs.info2[i].num_storages)) - return False; - } - for(i=0;idfs.info2[i].entrypath, ctr->dfs.info2[i].ptr_entrypath, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - if(!smb_io_unistr2("",&ctr->dfs.info2[i].comment, ctr->dfs.info2[i].ptr_comment, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - } - depth--; - break; - case 3: - depth++; - if(UNMARSHALLING(ps)) { - ctr->dfs.info3 = PRS_ALLOC_MEM(ps, DFS_INFO_3, num_entries); - if (!ctr->dfs.info3) - return False; + uint32 i_stores_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info4_d"); + depth++; + if (v->ptr0_path) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + } + + if (v->ptr0_comment) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("comment", &v->comment, 1, ps, depth)) + return False; + } + + + + + + if (v->ptr0_stores) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_stores", ps, depth, &v->size_stores)) + return False; + + if (UNMARSHALLING(ps)) { + v->stores = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->stores)*v->num_stores); } - - for(i=0;idfs.info3[i].ptr_entrypath)) - return False; - if(!prs_uint32("ptr_comment", ps, depth, &ctr->dfs.info3[i].ptr_comment)) - return False; - if(!prs_uint32("state", ps, depth, &ctr->dfs.info3[i].state)) - return False; - if(!prs_uint32("num_storages", ps, depth, &ctr->dfs.info3[i].num_storages)) - return False; - if(!prs_uint32("ptr_storages", ps, depth, &ctr->dfs.info3[i].ptr_storages)) + for (i_stores_1=0; i_stores_1num_stores;i_stores_1++) { + if (!netdfs_io_dfs_StorageInfo_p("stores", &v->stores[i_stores_1], ps, depth)) return False; } - for(i=0;idfs.info3[i].entrypath, ctr->dfs.info3[i].ptr_entrypath, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - if(!smb_io_unistr2("", &ctr->dfs.info3[i].comment, ctr->dfs.info3[i].ptr_comment, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - if(!prs_uint32("num_storage_infos", ps, depth, &ctr->dfs.info3[i].num_storage_infos)) - return False; - - if(!dfs_io_dfs_storage_info("storage_info", &ctr->dfs.info3[i], ps, depth)) + for (i_stores_1=0; i_stores_1num_stores;i_stores_1++) { + if (!netdfs_io_dfs_StorageInfo_d("stores", &v->stores[i_stores_1], ps, depth)) return False; } } - + return True; } -/************************************************************ - Read/write a DFS_R_DFS_ENUM structure - ************************************************************/ +BOOL init_netdfs_dfs_Info100(NETDFS_DFS_INFO100 *v, const char *comment) +{ + DEBUG(5,("init_netdfs_dfs_Info100\n")); + + if (comment) { + v->ptr0_comment = 1; + init_unistr2(&v->comment, comment, UNI_FLAGS_NONE); + } else { + v->ptr0_comment = 0; + } + + return True; +} -BOOL dfs_io_r_dfs_enum(const char *desc, DFS_R_DFS_ENUM *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info100_p(const char *desc, NETDFS_DFS_INFO100 *v, prs_struct *ps, int depth) { - DFS_INFO_CTR *ctr; - if(q_d == NULL) + if (v == NULL) return False; - ctr = q_d->ctr; - if(ctr == NULL) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info100_p"); + depth++; + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; + + + return True; +} - prs_debug(ps, depth, desc, "dfs_io_r_dfs_enum"); +BOOL netdfs_io_dfs_Info100_d(const char *desc, NETDFS_DFS_INFO100 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info100_d"); depth++; + if (v->ptr0_comment) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("comment", &v->comment, 1, ps, depth)) + return False; + } + + return True; +} - if(!prs_align(ps)) - return False; +BOOL init_netdfs_dfs_Info101(NETDFS_DFS_INFO101 *v, uint32 state) +{ + DEBUG(5,("init_netdfs_dfs_Info101\n")); + + v->state = state; + + return True; +} - if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer)) +BOOL netdfs_io_dfs_Info101_p(const char *desc, NETDFS_DFS_INFO101 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(!prs_uint32("level", ps, depth, &q_d->level)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info101_p"); + depth++; + if (!prs_uint32("state", ps, depth, &v->state)) return False; - if(!prs_uint32("level2", ps, depth, &ctr->switch_value)) + + return True; +} + +BOOL netdfs_io_dfs_Info101_d(const char *desc, NETDFS_DFS_INFO101 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(!prs_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info101_d"); + depth++; + + return True; +} + +BOOL init_netdfs_dfs_Info102(NETDFS_DFS_INFO102 *v, uint32 timeout) +{ + DEBUG(5,("init_netdfs_dfs_Info102\n")); + + v->timeout = timeout; + + return True; +} + +BOOL netdfs_io_dfs_Info102_p(const char *desc, NETDFS_DFS_INFO102 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(q_d->ptr_num_entries) - if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries)) - return False; - if(!prs_uint32("ptr_num_entries2", ps, depth, &q_d->ptr_num_entries2)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info102_p"); + depth++; + if (!prs_uint32("timeout", ps, depth, &v->timeout)) return False; - if(q_d->ptr_num_entries2) - if(!prs_uint32("num_entries2", ps, depth, &ctr->num_entries)) - return False; + + return True; +} - if(!dfs_io_dfs_info_ctr("", ctr, q_d->num_entries, q_d->level, ps, depth)) +BOOL netdfs_io_dfs_Info102_d(const char *desc, NETDFS_DFS_INFO102 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info102_d"); + depth++; + + return True; +} + +BOOL init_netdfs_dfs_Info200(NETDFS_DFS_INFO200 *v, const char *dom_root) +{ + DEBUG(5,("init_netdfs_dfs_Info200\n")); + + if (dom_root) { + v->ptr0_dom_root = 1; + init_unistr2(&v->dom_root, dom_root, UNI_FLAGS_NONE); + } else { + v->ptr0_dom_root = 0; + } + + return True; +} - if(!smb_io_enum_hnd("resume_hnd", &q_d->reshnd, ps, depth)) +BOOL netdfs_io_dfs_Info200_p(const char *desc, NETDFS_DFS_INFO200 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(!prs_werror("status", ps, depth, &q_d->status)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info200_p"); + depth++; + if (!prs_uint32("ptr0_dom_root", ps, depth, &v->ptr0_dom_root)) return False; + + return True; } -BOOL dfs_io_dfs_storage_info(const char *desc, DFS_INFO_3* info3, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info200_d(const char *desc, NETDFS_DFS_INFO200 *v, prs_struct *ps, int depth) { - int i=0; - if(info3 == NULL) + if (v == NULL) return False; - - prs_debug(ps, depth, desc, "smb_io_dfs_storage_info"); + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info200_d"); depth++; - - if(UNMARSHALLING(ps)) { - info3->storages = PRS_ALLOC_MEM(ps, DFS_STORAGE_INFO, info3->num_storage_infos); - if (!info3->storages) + if (v->ptr0_dom_root) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("dom_root", &v->dom_root, 1, ps, depth)) return False; } + + return True; +} - for(i=0;inum_storage_infos;i++) { - if(!prs_uint32("storage_state", ps, depth, &info3->storages[i].state)) - return False; - if(!prs_uint32("ptr_servername", ps, depth, &info3->storages[i].ptr_servername)) - return False; - if(!prs_uint32("ptr_sharename", ps, depth, &info3->storages[i].ptr_sharename)) - return False; +BOOL init_netdfs_dfs_Info300(NETDFS_DFS_INFO300 *v, uint32 flags, const char *dom_root) +{ + DEBUG(5,("init_netdfs_dfs_Info300\n")); + + v->flags = flags; + + if (dom_root) { + v->ptr0_dom_root = 1; + init_unistr2(&v->dom_root, dom_root, UNI_FLAGS_NONE); + } else { + v->ptr0_dom_root = 0; } + + return True; +} - for(i=0;inum_storage_infos;i++) { - if(!smb_io_unistr2("servername", &info3->storages[i].servername, info3->storages[i].ptr_servername, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - if(!smb_io_unistr2("sharename", &info3->storages[i].sharename, info3->storages[i].ptr_sharename, ps, depth)) +BOOL netdfs_io_dfs_Info300_p(const char *desc, NETDFS_DFS_INFO300 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info300_p"); + depth++; + if (!prs_uint32("flags", ps, depth, &v->flags)) + return False; + + if (!prs_uint32("ptr0_dom_root", ps, depth, &v->ptr0_dom_root)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_Info300_d(const char *desc, NETDFS_DFS_INFO300 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info300_d"); + depth++; + + if (v->ptr0_dom_root) { + if (!prs_align_custom(ps, 4)) return False; - if(!prs_align(ps)) + + if (!smb_io_unistr2("dom_root", &v->dom_root, 1, ps, depth)) return False; } - + return True; } + +BOOL netdfs_io_dfs_Info_p(const char *desc, NETDFS_DFS_INFO_CTR* v, prs_struct *ps, int depth) +{ + if (!prs_uint32("switch_value", ps, depth, &v->switch_value)) + return False; + + switch (v->switch_value) { + case 0: + depth++; + if (!prs_uint32("ptr0_info0", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 1: + depth++; + if (!prs_uint32("ptr0_info1", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 2: + depth++; + if (!prs_uint32("ptr0_info2", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 3: + depth++; + if (!prs_uint32("ptr0_info3", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 4: + depth++; + if (!prs_uint32("ptr0_info4", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 100: + depth++; + if (!prs_uint32("ptr0_info100", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 101: + depth++; + if (!prs_uint32("ptr0_info101", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 102: + depth++; + if (!prs_uint32("ptr0_info102", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + default: + return False; + + } + + return True; +} + +BOOL netdfs_io_dfs_Info_d(const char *desc, NETDFS_DFS_INFO_CTR* v, prs_struct *ps, int depth) +{ + switch (v->switch_value) { + case 0: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 1)) + return False; + + if (!netdfs_io_dfs_Info0_p("info0", &v->u.info0, ps, depth)) + return False; + if (!netdfs_io_dfs_Info0_d("info0", &v->u.info0, ps, depth)) + return False; + } + depth--; + break; + + case 1: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info1_p("info1", &v->u.info1, ps, depth)) + return False; + if (!netdfs_io_dfs_Info1_d("info1", &v->u.info1, ps, depth)) + return False; + } + depth--; + break; + + case 2: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info2_p("info2", &v->u.info2, ps, depth)) + return False; + if (!netdfs_io_dfs_Info2_d("info2", &v->u.info2, ps, depth)) + return False; + } + depth--; + break; + + case 3: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info3_p("info3", &v->u.info3, ps, depth)) + return False; + if (!netdfs_io_dfs_Info3_d("info3", &v->u.info3, ps, depth)) + return False; + } + depth--; + break; + + case 4: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info4_p("info4", &v->u.info4, ps, depth)) + return False; + if (!netdfs_io_dfs_Info4_d("info4", &v->u.info4, ps, depth)) + return False; + } + depth--; + break; + + case 100: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info100_p("info100", &v->u.info100, ps, depth)) + return False; + if (!netdfs_io_dfs_Info100_d("info100", &v->u.info100, ps, depth)) + return False; + } + depth--; + break; + + case 101: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info101_p("info101", &v->u.info101, ps, depth)) + return False; + if (!netdfs_io_dfs_Info101_d("info101", &v->u.info101, ps, depth)) + return False; + } + depth--; + break; + + case 102: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_Info102_p("info102", &v->u.info102, ps, depth)) + return False; + if (!netdfs_io_dfs_Info102_d("info102", &v->u.info102, ps, depth)) + return False; + } + depth--; + break; + + } + + return True; +} +BOOL init_netdfs_dfs_EnumArray1(NETDFS_DFS_ENUMARRAY1 *v, uint32 count, NETDFS_DFS_INFO1 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray1\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray1_p(const char *desc, NETDFS_DFS_ENUMARRAY1 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray1_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray1_d(const char *desc, NETDFS_DFS_ENUMARRAY1 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray1_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info1_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info1_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL init_netdfs_dfs_EnumArray2(NETDFS_DFS_ENUMARRAY2 *v, uint32 count, NETDFS_DFS_INFO2 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray2\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray2_p(const char *desc, NETDFS_DFS_ENUMARRAY2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray2_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray2_d(const char *desc, NETDFS_DFS_ENUMARRAY2 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray2_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info2_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info2_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL init_netdfs_dfs_EnumArray3(NETDFS_DFS_ENUMARRAY3 *v, uint32 count, NETDFS_DFS_INFO3 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray3\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray3_p(const char *desc, NETDFS_DFS_ENUMARRAY3 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray3_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray3_d(const char *desc, NETDFS_DFS_ENUMARRAY3 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray3_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info3_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info3_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL init_netdfs_dfs_EnumArray4(NETDFS_DFS_ENUMARRAY4 *v, uint32 count, NETDFS_DFS_INFO4 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray4\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray4_p(const char *desc, NETDFS_DFS_ENUMARRAY4 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray4_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray4_d(const char *desc, NETDFS_DFS_ENUMARRAY4 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray4_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info4_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info4_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL init_netdfs_dfs_EnumArray200(NETDFS_DFS_ENUMARRAY200 *v, uint32 count, NETDFS_DFS_INFO200 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray200\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray200_p(const char *desc, NETDFS_DFS_ENUMARRAY200 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray200_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray200_d(const char *desc, NETDFS_DFS_ENUMARRAY200 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray200_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info200_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info200_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL init_netdfs_dfs_EnumArray300(NETDFS_DFS_ENUMARRAY300 *v, uint32 count, NETDFS_DFS_INFO300 **s) +{ + DEBUG(5,("init_netdfs_dfs_EnumArray300\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 0; + } + + return True; +} + +BOOL netdfs_io_dfs_EnumArray300_p(const char *desc, NETDFS_DFS_ENUMARRAY300 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray300_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) + return False; + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) + return False; + + + return True; +} + +BOOL netdfs_io_dfs_EnumArray300_d(const char *desc, NETDFS_DFS_ENUMARRAY300 *v, prs_struct *ps, int depth) +{ + uint32 i_s_1; + + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray300_d"); + depth++; + + if (v->ptr0_s) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("size_s", ps, depth, &v->size_s)) + return False; + + if (UNMARSHALLING(ps)) { + v->s = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*v->s)*v->count); + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info300_p("s", &v->s[i_s_1], ps, depth)) + return False; + } + for (i_s_1=0; i_s_1count;i_s_1++) { + if (!netdfs_io_dfs_Info300_d("s", &v->s[i_s_1], ps, depth)) + return False; + } + } + + return True; +} + +BOOL netdfs_io_dfs_EnumInfo_p(const char *desc, NETDFS_DFS_ENUMINFO_CTR* v, prs_struct *ps, int depth) +{ + if (!prs_uint32("switch_value", ps, depth, &v->switch_value)) + return False; + + switch (v->switch_value) { + case 1: + depth++; + if (!prs_uint32("ptr0_info1", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 2: + depth++; + if (!prs_uint32("ptr0_info2", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 3: + depth++; + if (!prs_uint32("ptr0_info3", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 4: + depth++; + if (!prs_uint32("ptr0_info4", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 200: + depth++; + if (!prs_uint32("ptr0_info200", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + case 300: + depth++; + if (!prs_uint32("ptr0_info300", ps, depth, &v->ptr0)) + return False; + + depth--; + break; + + default: + return False; + + } + + return True; +} + +BOOL netdfs_io_dfs_EnumInfo_d(const char *desc, NETDFS_DFS_ENUMINFO_CTR* v, prs_struct *ps, int depth) +{ + switch (v->switch_value) { + case 1: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray1_p("info1", &v->u.info1, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray1_d("info1", &v->u.info1, ps, depth)) + return False; + } + depth--; + break; + + case 2: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray2_p("info2", &v->u.info2, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray2_d("info2", &v->u.info2, ps, depth)) + return False; + } + depth--; + break; + + case 3: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray3_p("info3", &v->u.info3, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray3_d("info3", &v->u.info3, ps, depth)) + return False; + } + depth--; + break; + + case 4: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray4_p("info4", &v->u.info4, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray4_d("info4", &v->u.info4, ps, depth)) + return False; + } + depth--; + break; + + case 200: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray200_p("info200", &v->u.info200, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray200_d("info200", &v->u.info200, ps, depth)) + return False; + } + depth--; + break; + + case 300: + depth++; + if (v->ptr0) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumArray300_p("info300", &v->u.info300, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumArray300_d("info300", &v->u.info300, ps, depth)) + return False; + } + depth--; + break; + + } + + return True; +} +BOOL init_netdfs_dfs_EnumStruct(NETDFS_DFS_ENUMSTRUCT *v, uint32 level, NETDFS_DFS_ENUMINFO_CTR e) +{ + DEBUG(5,("init_netdfs_dfs_EnumStruct\n")); + + v->level = level; + + v->e = e; + v->e.switch_value = v->level; + + return True; +} + +BOOL netdfs_io_dfs_EnumStruct_p(const char *desc, NETDFS_DFS_ENUMSTRUCT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumStruct_p"); + depth++; + if (!prs_uint32("level", ps, depth, &v->level)) + return False; + + if (!netdfs_io_dfs_EnumInfo_p("e", &v->e, ps, depth)) + return False; + + return True; +} + +BOOL netdfs_io_dfs_EnumStruct_d(const char *desc, NETDFS_DFS_ENUMSTRUCT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumStruct_d"); + depth++; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!netdfs_io_dfs_EnumInfo_d("e", &v->e, ps, depth)) + return False; + + return True; +} + +/* netdfs functions */ +BOOL init_netdfs_q_dfs_GetManagerVersion(NETDFS_Q_DFS_GETMANAGERVERSION *v) +{ + DEBUG(5,("init_netdfs_q_dfs_GetManagerVersion\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_GetManagerVersion(const char *desc, NETDFS_Q_DFS_GETMANAGERVERSION *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_GetManagerVersion"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_GetManagerVersion(NETDFS_R_DFS_GETMANAGERVERSION *v, uint32 *exist_flag) +{ + DEBUG(5,("init_netdfs_r_dfs_GetManagerVersion\n")); + + if (!exist_flag) + return False; + + v->exist_flag = *exist_flag; + + return True; +} + +BOOL netdfs_io_r_dfs_GetManagerVersion(const char *desc, NETDFS_R_DFS_GETMANAGERVERSION *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_GetManagerVersion"); + depth++; + if (!prs_uint32("exist_flag", ps, depth, &v->exist_flag)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Add(NETDFS_Q_DFS_ADD *v, const char *path, const char *server, const char *share, const char *comment, uint32 flags) +{ + DEBUG(5,("init_netdfs_q_dfs_Add\n")); + + if (!path) + return False; + + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + + if (!server) + return False; + + init_unistr2(&v->server, server, UNI_FLAGS_NONE); + + if (share) { + v->ptr0_share = 1; + init_unistr2(&v->share, share, UNI_FLAGS_NONE); + } else { + v->ptr0_share = 0; + } + + if (comment) { + v->ptr0_comment = 1; + init_unistr2(&v->comment, comment, UNI_FLAGS_NONE); + } else { + v->ptr0_comment = 0; + } + + v->flags = flags; + + return True; +} + +BOOL netdfs_io_q_dfs_Add(const char *desc, NETDFS_Q_DFS_ADD *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Add"); + depth++; + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("server", &v->server, 1, ps, depth)) + return False; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_share", ps, depth, &v->ptr0_share)) + return False; + + if (v->ptr0_share) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("share", &v->share, 1, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) + return False; + + if (v->ptr0_comment) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("comment", &v->comment, 1, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("flags", ps, depth, &v->flags)) + return False; + + return True; +} + +BOOL init_netdfs_r_dfs_Add(NETDFS_R_DFS_ADD *v, const char *path, const char *server, const char *share, const char *comment, uint32 flags, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Add\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Add(const char *desc, NETDFS_R_DFS_ADD *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Add"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Remove(NETDFS_Q_DFS_REMOVE *v, const char *path, const char *server, const char *share) +{ + DEBUG(5,("init_netdfs_q_dfs_Remove\n")); + + if (!path) + return False; + + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + + if (server) { + v->ptr0_server = 1; + init_unistr2(&v->server, server, UNI_FLAGS_NONE); + } else { + v->ptr0_server = 0; + } + + if (share) { + v->ptr0_share = 1; + init_unistr2(&v->share, share, UNI_FLAGS_NONE); + } else { + v->ptr0_share = 0; + } + + return True; +} + +BOOL netdfs_io_q_dfs_Remove(const char *desc, NETDFS_Q_DFS_REMOVE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Remove"); + depth++; + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_server", ps, depth, &v->ptr0_server)) + return False; + + if (v->ptr0_server) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("server", &v->server, 1, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_share", ps, depth, &v->ptr0_share)) + return False; + + if (v->ptr0_share) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("share", &v->share, 1, ps, depth)) + return False; + } + + return True; +} + +BOOL init_netdfs_r_dfs_Remove(NETDFS_R_DFS_REMOVE *v, const char *path, const char *server, const char *share, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Remove\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Remove(const char *desc, NETDFS_R_DFS_REMOVE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Remove"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_SetInfo(NETDFS_Q_DFS_SETINFO *v) +{ + DEBUG(5,("init_netdfs_q_dfs_SetInfo\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_SetInfo(const char *desc, NETDFS_Q_DFS_SETINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_SetInfo"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_SetInfo(NETDFS_R_DFS_SETINFO *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_SetInfo\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_SetInfo(const char *desc, NETDFS_R_DFS_SETINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_SetInfo"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_GetInfo(NETDFS_Q_DFS_GETINFO *v, const char *path, const char *server, const char *share, uint32 level) +{ + DEBUG(5,("init_netdfs_q_dfs_GetInfo\n")); + + if (!path) + return False; + + init_unistr2(&v->path, path, UNI_FLAGS_NONE); + + if (server) { + v->ptr0_server = 1; + init_unistr2(&v->server, server, UNI_FLAGS_NONE); + } else { + v->ptr0_server = 0; + } + + if (share) { + v->ptr0_share = 1; + init_unistr2(&v->share, share, UNI_FLAGS_NONE); + } else { + v->ptr0_share = 0; + } + + v->level = level; + + return True; +} + +BOOL netdfs_io_q_dfs_GetInfo(const char *desc, NETDFS_Q_DFS_GETINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_GetInfo"); + depth++; + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("path", &v->path, 1, ps, depth)) + return False; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_server", ps, depth, &v->ptr0_server)) + return False; + + if (v->ptr0_server) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("server", &v->server, 1, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_share", ps, depth, &v->ptr0_share)) + return False; + + if (v->ptr0_share) { + if (!prs_align_custom(ps, 4)) + return False; + + if (!smb_io_unistr2("share", &v->share, 1, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("level", ps, depth, &v->level)) + return False; + + return True; +} + +BOOL init_netdfs_r_dfs_GetInfo(NETDFS_R_DFS_GETINFO *v, const char *path, const char *server, const char *share, uint32 level, NETDFS_DFS_INFO_CTR *info, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_GetInfo\n")); + + if (!info) + return False; + + v->info = *info; + v->info.switch_value = level; + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_GetInfo(const char *desc, NETDFS_R_DFS_GETINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_GetInfo"); + depth++; + if (!netdfs_io_dfs_Info_p("info", &v->info, ps, depth)) + return False; + if (!netdfs_io_dfs_Info_d("info", &v->info, ps, depth)) + return False; + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Enum(NETDFS_Q_DFS_ENUM *v, uint32 level, uint32 bufsize, NETDFS_DFS_ENUMSTRUCT *info, uint32 *unknown, uint32 *total) +{ + DEBUG(5,("init_netdfs_q_dfs_Enum\n")); + + v->level = level; + + v->bufsize = bufsize; + + if (info) { + v->ptr0_info = 1; + v->info = *info; + } else { + v->ptr0_info = 0; + } + + if (unknown) { + v->ptr0_unknown = 1; + v->unknown = *unknown; + } else { + v->ptr0_unknown = 0; + } + + if (total) { + v->ptr0_total = 1; + v->total = *total; + } else { + v->ptr0_total = 0; + } + + return True; +} + +BOOL netdfs_io_q_dfs_Enum(const char *desc, NETDFS_Q_DFS_ENUM *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Enum"); + depth++; + if (!prs_uint32("level", ps, depth, &v->level)) + return False; + + if (!prs_uint32("bufsize", ps, depth, &v->bufsize)) + return False; + + if (!prs_uint32("ptr0_info", ps, depth, &v->ptr0_info)) + return False; + + if (v->ptr0_info) { + if (!netdfs_io_dfs_EnumStruct_p("info", &v->info, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumStruct_d("info", &v->info, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_unknown", ps, depth, &v->ptr0_unknown)) + return False; + + if (v->ptr0_unknown) { + if (!prs_uint32("unknown", ps, depth, &v->unknown)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_total", ps, depth, &v->ptr0_total)) + return False; + + if (v->ptr0_total) { + if (!prs_uint32("total", ps, depth, &v->total)) + return False; + } + + return True; +} + +BOOL init_netdfs_r_dfs_Enum(NETDFS_R_DFS_ENUM *v, uint32 level, uint32 bufsize, NETDFS_DFS_ENUMSTRUCT *info, uint32 *unknown, uint32 *total, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Enum\n")); + + if (info) { + v->ptr0_info = 1; + v->info = *info; + } else { + v->ptr0_info = 0; + } + + if (total) { + v->ptr0_total = 1; + v->total = *total; + } else { + v->ptr0_total = 0; + } + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Enum(const char *desc, NETDFS_R_DFS_ENUM *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Enum"); + depth++; + if (!prs_uint32("ptr0_info", ps, depth, &v->ptr0_info)) + return False; + + if (v->ptr0_info) { + if (!netdfs_io_dfs_EnumStruct_p("info", &v->info, ps, depth)) + return False; + if (!netdfs_io_dfs_EnumStruct_d("info", &v->info, ps, depth)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_total", ps, depth, &v->ptr0_total)) + return False; + + if (v->ptr0_total) { + if (!prs_uint32("total", ps, depth, &v->total)) + return False; + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Rename(NETDFS_Q_DFS_RENAME *v) +{ + DEBUG(5,("init_netdfs_q_dfs_Rename\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_Rename(const char *desc, NETDFS_Q_DFS_RENAME *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Rename"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_Rename(NETDFS_R_DFS_RENAME *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Rename\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Rename(const char *desc, NETDFS_R_DFS_RENAME *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Rename"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Move(NETDFS_Q_DFS_MOVE *v) +{ + DEBUG(5,("init_netdfs_q_dfs_Move\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_Move(const char *desc, NETDFS_Q_DFS_MOVE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Move"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_Move(NETDFS_R_DFS_MOVE *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Move\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Move(const char *desc, NETDFS_R_DFS_MOVE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Move"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_ManagerGetConfigInfo(NETDFS_Q_DFS_MANAGERGETCONFIGINFO *v) +{ + DEBUG(5,("init_netdfs_q_dfs_ManagerGetConfigInfo\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_ManagerGetConfigInfo(const char *desc, NETDFS_Q_DFS_MANAGERGETCONFIGINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_ManagerGetConfigInfo"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_ManagerGetConfigInfo(NETDFS_R_DFS_MANAGERGETCONFIGINFO *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_ManagerGetConfigInfo\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_ManagerGetConfigInfo(const char *desc, NETDFS_R_DFS_MANAGERGETCONFIGINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_ManagerGetConfigInfo"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_ManagerSendSiteInfo(NETDFS_Q_DFS_MANAGERSENDSITEINFO *v) +{ + DEBUG(5,("init_netdfs_q_dfs_ManagerSendSiteInfo\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_ManagerSendSiteInfo(const char *desc, NETDFS_Q_DFS_MANAGERSENDSITEINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_ManagerSendSiteInfo"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_ManagerSendSiteInfo(NETDFS_R_DFS_MANAGERSENDSITEINFO *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_ManagerSendSiteInfo\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_ManagerSendSiteInfo(const char *desc, NETDFS_R_DFS_MANAGERSENDSITEINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_ManagerSendSiteInfo"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_AddFtRoot(NETDFS_Q_DFS_ADDFTROOT *v) +{ + DEBUG(5,("init_netdfs_q_dfs_AddFtRoot\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_AddFtRoot(const char *desc, NETDFS_Q_DFS_ADDFTROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_AddFtRoot"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_AddFtRoot(NETDFS_R_DFS_ADDFTROOT *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_AddFtRoot\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_AddFtRoot(const char *desc, NETDFS_R_DFS_ADDFTROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_AddFtRoot"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_RemoveFtRoot(NETDFS_Q_DFS_REMOVEFTROOT *v) +{ + DEBUG(5,("init_netdfs_q_dfs_RemoveFtRoot\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_RemoveFtRoot(const char *desc, NETDFS_Q_DFS_REMOVEFTROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_RemoveFtRoot"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_RemoveFtRoot(NETDFS_R_DFS_REMOVEFTROOT *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_RemoveFtRoot\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_RemoveFtRoot(const char *desc, NETDFS_R_DFS_REMOVEFTROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_RemoveFtRoot"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_AddStdRoot(NETDFS_Q_DFS_ADDSTDROOT *v) +{ + DEBUG(5,("init_netdfs_q_dfs_AddStdRoot\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_AddStdRoot(const char *desc, NETDFS_Q_DFS_ADDSTDROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_AddStdRoot"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_AddStdRoot(NETDFS_R_DFS_ADDSTDROOT *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_AddStdRoot\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_AddStdRoot(const char *desc, NETDFS_R_DFS_ADDSTDROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_AddStdRoot"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_RemoveStdRoot(NETDFS_Q_DFS_REMOVESTDROOT *v) +{ + DEBUG(5,("init_netdfs_q_dfs_RemoveStdRoot\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_RemoveStdRoot(const char *desc, NETDFS_Q_DFS_REMOVESTDROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_RemoveStdRoot"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_RemoveStdRoot(NETDFS_R_DFS_REMOVESTDROOT *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_RemoveStdRoot\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_RemoveStdRoot(const char *desc, NETDFS_R_DFS_REMOVESTDROOT *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_RemoveStdRoot"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_ManagerInitialize(NETDFS_Q_DFS_MANAGERINITIALIZE *v) +{ + DEBUG(5,("init_netdfs_q_dfs_ManagerInitialize\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_ManagerInitialize(const char *desc, NETDFS_Q_DFS_MANAGERINITIALIZE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_ManagerInitialize"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_ManagerInitialize(NETDFS_R_DFS_MANAGERINITIALIZE *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_ManagerInitialize\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_ManagerInitialize(const char *desc, NETDFS_R_DFS_MANAGERINITIALIZE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_ManagerInitialize"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_AddStdRootForced(NETDFS_Q_DFS_ADDSTDROOTFORCED *v) +{ + DEBUG(5,("init_netdfs_q_dfs_AddStdRootForced\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_AddStdRootForced(const char *desc, NETDFS_Q_DFS_ADDSTDROOTFORCED *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_AddStdRootForced"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_AddStdRootForced(NETDFS_R_DFS_ADDSTDROOTFORCED *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_AddStdRootForced\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_AddStdRootForced(const char *desc, NETDFS_R_DFS_ADDSTDROOTFORCED *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_AddStdRootForced"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_GetDcAddress(NETDFS_Q_DFS_GETDCADDRESS *v) +{ + DEBUG(5,("init_netdfs_q_dfs_GetDcAddress\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_GetDcAddress(const char *desc, NETDFS_Q_DFS_GETDCADDRESS *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_GetDcAddress"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_GetDcAddress(NETDFS_R_DFS_GETDCADDRESS *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_GetDcAddress\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_GetDcAddress(const char *desc, NETDFS_R_DFS_GETDCADDRESS *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_GetDcAddress"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_SetDcAddress(NETDFS_Q_DFS_SETDCADDRESS *v) +{ + DEBUG(5,("init_netdfs_q_dfs_SetDcAddress\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_SetDcAddress(const char *desc, NETDFS_Q_DFS_SETDCADDRESS *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_SetDcAddress"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_SetDcAddress(NETDFS_R_DFS_SETDCADDRESS *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_SetDcAddress\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_SetDcAddress(const char *desc, NETDFS_R_DFS_SETDCADDRESS *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_SetDcAddress"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_FlushFtTable(NETDFS_Q_DFS_FLUSHFTTABLE *v) +{ + DEBUG(5,("init_netdfs_q_dfs_FlushFtTable\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_FlushFtTable(const char *desc, NETDFS_Q_DFS_FLUSHFTTABLE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_FlushFtTable"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_FlushFtTable(NETDFS_R_DFS_FLUSHFTTABLE *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_FlushFtTable\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_FlushFtTable(const char *desc, NETDFS_R_DFS_FLUSHFTTABLE *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_FlushFtTable"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Add2(NETDFS_Q_DFS_ADD2 *v) +{ + DEBUG(5,("init_netdfs_q_dfs_Add2\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_Add2(const char *desc, NETDFS_Q_DFS_ADD2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Add2"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_Add2(NETDFS_R_DFS_ADD2 *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Add2\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Add2(const char *desc, NETDFS_R_DFS_ADD2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Add2"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_Remove2(NETDFS_Q_DFS_REMOVE2 *v) +{ + DEBUG(5,("init_netdfs_q_dfs_Remove2\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_Remove2(const char *desc, NETDFS_Q_DFS_REMOVE2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_Remove2"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_Remove2(NETDFS_R_DFS_REMOVE2 *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_Remove2\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_Remove2(const char *desc, NETDFS_R_DFS_REMOVE2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Remove2"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_EnumEx(NETDFS_Q_DFS_ENUMEX *v) +{ + DEBUG(5,("init_netdfs_q_dfs_EnumEx\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_EnumEx(const char *desc, NETDFS_Q_DFS_ENUMEX *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_EnumEx"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_EnumEx(NETDFS_R_DFS_ENUMEX *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_EnumEx\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_EnumEx(const char *desc, NETDFS_R_DFS_ENUMEX *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_EnumEx"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + +BOOL init_netdfs_q_dfs_SetInfo2(NETDFS_Q_DFS_SETINFO2 *v) +{ + DEBUG(5,("init_netdfs_q_dfs_SetInfo2\n")); + + return True; +} + +BOOL netdfs_io_q_dfs_SetInfo2(const char *desc, NETDFS_Q_DFS_SETINFO2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_q_dfs_SetInfo2"); + depth++; + return True; +} + +BOOL init_netdfs_r_dfs_SetInfo2(NETDFS_R_DFS_SETINFO2 *v, WERROR status) +{ + DEBUG(5,("init_netdfs_r_dfs_SetInfo2\n")); + + v->status = status; + + return True; +} + +BOOL netdfs_io_r_dfs_SetInfo2(const char *desc, NETDFS_R_DFS_SETINFO2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_SetInfo2"); + depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} + diff --git a/source/rpc_parse/parse_lsa.c b/source/rpc_parse/parse_lsa.c index 3d28b657f33..1edc0175106 100644 --- a/source/rpc_parse/parse_lsa.c +++ b/source/rpc_parse/parse_lsa.c @@ -508,8 +508,9 @@ BOOL lsa_io_q_enum_trust_dom(const char *desc, LSA_Q_ENUM_TRUST_DOM *q_e, Inits an LSA_R_ENUM_TRUST_DOM structure. ********************************************************************/ -void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *out, uint32 enum_context, - uint32 req_num_domains, uint32 num_domains, TRUSTDOM **td) +void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *out, + uint32 enum_context, uint32 num_domains, + struct trustdom_info **td) { unsigned int i; @@ -523,7 +524,8 @@ void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *out, uint32 en /* allocate container memory */ out->domlist = TALLOC_P( ctx, DOMAIN_LIST ); - out->domlist->domains = TALLOC_ARRAY( ctx, DOMAIN_INFO, out->count ); + out->domlist->domains = TALLOC_ARRAY( ctx, DOMAIN_INFO, + out->count ); if ( !out->domlist || !out->domlist->domains ) { out->status = NT_STATUS_NO_MEMORY; @@ -535,13 +537,21 @@ void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *out, uint32 en /* initialize the list of domains and their sid */ for (i = 0; i < num_domains; i++) { - if ( !(out->domlist->domains[i].sid = TALLOC_P(ctx, DOM_SID2)) ) { + smb_ucs2_t *name; + if ( !(out->domlist->domains[i].sid = + TALLOC_P(ctx, DOM_SID2)) ) { out->status = NT_STATUS_NO_MEMORY; return; } - init_dom_sid2(out->domlist->domains[i].sid, &(td[i])->sid); - init_unistr4_w(ctx, &out->domlist->domains[i].name, (td[i])->name); + init_dom_sid2(out->domlist->domains[i].sid, + &(td[i])->sid); + if (push_ucs2_talloc(ctx, &name, (td[i])->name) < 0){ + out->status = NT_STATUS_NO_MEMORY; + return; + } + init_unistr4_w(ctx, &out->domlist->domains[i].name, + name); } } @@ -2539,8 +2549,78 @@ BOOL lsa_io_q_open_trusted_domain(const char *desc, LSA_Q_OPEN_TRUSTED_DOMAIN *i } #endif + +/******************************************************************* + Inits an LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME structure. +********************************************************************/ + +void init_lsa_q_open_trusted_domain_by_name(LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME *q, + POLICY_HND *hnd, + const char *name, + uint32 desired_access) +{ + memcpy(&q->pol, hnd, sizeof(q->pol)); + + init_lsa_string(&q->name, name); + q->access_mask = desired_access; +} + +/******************************************************************* +********************************************************************/ + + +/******************************************************************* + Reads or writes an LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME structure. +********************************************************************/ + +BOOL lsa_io_q_open_trusted_domain_by_name(const char *desc, LSA_Q_OPEN_TRUSTED_DOMAIN_BY_NAME *q_o, prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_q_open_trusted_domain_by_name"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!smb_io_pol_hnd("pol", &q_o->pol, ps, depth)) + return False; + + if(!prs_align(ps)) + return False; + + if(!smb_io_lsa_string("name", &q_o->name, ps, depth)) + return False; + + if(!prs_align(ps)) + return False; + + if(!prs_uint32("access", ps, depth, &q_o->access_mask)) + return False; + + return True; +} + +/******************************************************************* + Reads or writes an LSA_R_OPEN_TRUSTED_DOMAIN_BY_NAME structure. +********************************************************************/ + +BOOL lsa_io_r_open_trusted_domain_by_name(const char *desc, LSA_R_OPEN_TRUSTED_DOMAIN_BY_NAME *out, prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_r_open_trusted_domain_by_name"); + depth++; + + if(!prs_align(ps)) + return False; + + if (!smb_io_pol_hnd("handle", &out->handle, ps, depth)) + return False; + + if(!prs_ntstatus("status", ps, depth, &out->status)) + return False; + + return True; +} + /******************************************************************* - Reads or writes an LSA_Q_OPEN_TRUSTED_DOMAIN structure. ********************************************************************/ BOOL lsa_io_q_open_trusted_domain(const char *desc, LSA_Q_OPEN_TRUSTED_DOMAIN *q_o, prs_struct *ps, int depth) @@ -3111,3 +3191,130 @@ BOOL lsa_io_r_query_trusted_domain_info(const char *desc, return True; } +/******************************************************************* + Inits an LSA_Q_QUERY_DOM_INFO_POLICY structure. +********************************************************************/ + +void init_q_query_dom_info(LSA_Q_QUERY_DOM_INFO_POLICY *in, POLICY_HND *hnd, uint16 info_class) +{ + DEBUG(5, ("init_q_query_dom_info\n")); + + memcpy(&in->pol, hnd, sizeof(in->pol)); + + in->info_class = info_class; +} + +/******************************************************************* + Reads or writes an LSA_Q_QUERY_DOM_INFO_POLICY structure. +********************************************************************/ + +BOOL lsa_io_q_query_dom_info(const char *desc, LSA_Q_QUERY_DOM_INFO_POLICY *in, prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_q_query_dom_info"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!smb_io_pol_hnd("pol", &in->pol, ps, depth)) + return False; + + if(!prs_uint16("info_class", ps, depth, &in->info_class)) + return False; + + return True; +} + +/******************************************************************* + Reads or writes an LSA_R_QUERY_DOM_INFO_POLICY structure. +********************************************************************/ + +static BOOL lsa_io_dominfo_query_3(const char *desc, LSA_DOM_INFO_POLICY_KERBEROS *krb_policy, + prs_struct *ps, int depth) +{ + if (!prs_align_uint64(ps)) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_uint32("enforce_restrictions", ps, depth, &krb_policy->enforce_restrictions)) + return False; + + if (!prs_align_uint64(ps)) + return False; + + if (!smb_io_nttime("service_tkt_lifetime", ps, depth, &krb_policy->service_tkt_lifetime)) + return False; + + if (!prs_align_uint64(ps)) + return False; + + if (!smb_io_nttime("user_tkt_lifetime", ps, depth, &krb_policy->user_tkt_lifetime)) + return False; + + if (!prs_align_uint64(ps)) + return False; + + if (!smb_io_nttime("user_tkt_renewaltime", ps, depth, &krb_policy->user_tkt_renewaltime)) + return False; + + if (!prs_align_uint64(ps)) + return False; + + if (!smb_io_nttime("clock_skew", ps, depth, &krb_policy->clock_skew)) + return False; + + if (!prs_align_uint64(ps)) + return False; + + if (!smb_io_nttime("unknown6", ps, depth, &krb_policy->unknown6)) + return False; + + return True; +} + +static BOOL lsa_io_dom_info_query(const char *desc, prs_struct *ps, int depth, LSA_DOM_INFO_UNION *info) +{ + prs_debug(ps, depth, desc, "lsa_io_dom_info_query"); + depth++; + + if(!prs_align_uint16(ps)) + return False; + + if(!prs_uint16("info_class", ps, depth, &info->info_class)) + return False; + + switch (info->info_class) { + case 3: + if (!lsa_io_dominfo_query_3("krb_policy", &info->krb_policy, ps, depth)) + return False; + break; + default: + DEBUG(0,("unsupported info-level: %d\n", info->info_class)); + return False; + break; + } + + return True; +} + + +BOOL lsa_io_r_query_dom_info(const char *desc, LSA_R_QUERY_DOM_INFO_POLICY *out, + prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_r_query_dom_info"); + depth++; + + if (!prs_pointer("dominfo", ps, depth, (void**)&out->info, + sizeof(LSA_DOM_INFO_UNION), + (PRS_POINTER_CAST)lsa_io_dom_info_query) ) + return False; + + if(!prs_ntstatus("status", ps, depth, &out->status)) + return False; + + return True; +} + + diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c index 3bd6977dbb1..e7b1cdc767b 100644 --- a/source/rpc_parse/parse_net.c +++ b/source/rpc_parse/parse_net.c @@ -1396,7 +1396,7 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr, uint32 user_flgs, uchar user_session_key[16], uchar lm_session_key[16], const char *logon_srv, const char *logon_dom, - const DOM_SID *dom_sid, const char *other_sids) + const DOM_SID *dom_sid) { /* only cope with one "other" sid, right now. */ /* need to count the number of space-delimited sids */ @@ -1454,7 +1454,7 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr, memcpy(usr->lm_sess_key, lm_session_key, sizeof(usr->lm_sess_key)); } - num_other_sids = init_dom_sid2s(ctx, other_sids, &usr->other_sids); + num_other_sids = init_dom_sid2s(ctx, NULL, &usr->other_sids); usr->num_other_sids = num_other_sids; usr->buffer_other_sids = (num_other_sids != 0) ? 1 : 0; @@ -1488,6 +1488,47 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr, init_dom_sid2(&usr->dom_sid, dom_sid); /* "other" sids are set up above */ +} + + void dump_acct_flags(uint32 acct_flags) { + + int lvl = 10; + DEBUG(lvl,("dump_acct_flags\n")); + if (acct_flags & ACB_NORMAL) { + DEBUGADD(lvl,("\taccount has UF_NORMAL_ACCOUNT\n")); + } + if (acct_flags & ACB_PWNOEXP) { + DEBUGADD(lvl,("\taccount has UF_DONT_EXPIRE_PASSWD\n")); + } + if (acct_flags & ACB_ENC_TXT_PWD_ALLOWED) { + DEBUGADD(lvl,("\taccount has UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED\n")); + } + if (acct_flags & ACB_NOT_DELEGATED) { + DEBUGADD(lvl,("\taccount has UF_NOT_DELEGATED\n")); + } + if (acct_flags & ACB_USE_DES_KEY_ONLY) { + DEBUGADD(lvl,("\taccount has UF_USE_DES_KEY_ONLY set, sig verify wont work\n")); + } +} + + void dump_user_flgs(uint32 user_flags) { + + int lvl = 10; + DEBUG(lvl,("dump_user_flgs\n")); + if (user_flags & LOGON_EXTRA_SIDS) { + DEBUGADD(lvl,("\taccount has LOGON_EXTRA_SIDS\n")); + } + if (user_flags & LOGON_RESOURCE_GROUPS) { + DEBUGADD(lvl,("\taccount has LOGON_RESOURCE_GROUPS\n")); + } + if (user_flags & LOGON_NTLMV2_ENABLED) { + DEBUGADD(lvl,("\taccount has LOGON_NTLMV2_ENABLED\n")); + } + if (user_flags & LOGON_CACHED_ACCOUNT) { + DEBUGADD(lvl,("\taccount has LOGON_CACHED_ACCOUNT\n")); + } + + } /******************************************************************* @@ -1562,7 +1603,7 @@ BOOL net_io_user_info3(const char *desc, NET_USER_INFO_3 *usr, prs_struct *ps, return False; if(!prs_uint32("user_flgs ", ps, depth, &usr->user_flgs)) /* user flags */ return False; - + dump_user_flgs(usr->user_flgs); if(!prs_uint8s(False, "user_sess_key", ps, depth, usr->user_sess_key, 16)) /* user session key */ return False; @@ -1579,7 +1620,7 @@ BOOL net_io_user_info3(const char *desc, NET_USER_INFO_3 *usr, prs_struct *ps, if(!prs_uint32("acct_flags ", ps, depth, &usr->acct_flags)) /* Account flags */ return False; - + dump_acct_flags(usr->acct_flags); for (i = 0; i < 7; i++) { if (!prs_uint32("unkown", ps, depth, &usr->unknown[i])) /* unknown */ diff --git a/source/rpc_parse/parse_prs.c b/source/rpc_parse/parse_prs.c index 7c84ee800b9..c4f9f512ab7 100644 --- a/source/rpc_parse/parse_prs.c +++ b/source/rpc_parse/parse_prs.c @@ -1303,6 +1303,35 @@ BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_ return True; } +BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str) +{ + size_t len; + char *tmp_str; + + if (UNMARSHALLING(ps)) { + len = strlen(&ps->data_p[ps->data_offset]); + } else { + len = strlen(*str); + } + + tmp_str = PRS_ALLOC_MEM(ps, char, len+1); + + if (tmp_str == NULL) { + return False; + } + + if (MARSHALLING(ps)) { + strncpy(tmp_str, *str, len); + } + + if (!prs_string(name, ps, depth, tmp_str, len+1)) { + return False; + } + + *str = tmp_str; + return True; +} + /******************************************************************* prs_uint16 wrapper. Call this and it sets up a pointer to where the uint16 should be stored, or gets the size if reading. diff --git a/source/rpc_parse/parse_rpc.c b/source/rpc_parse/parse_rpc.c index ea4ec2c8639..544d139acb3 100644 --- a/source/rpc_parse/parse_rpc.c +++ b/source/rpc_parse/parse_rpc.c @@ -191,16 +191,6 @@ interface/version dce/rpc pipe identification }, 0x00 \ } -#define SYNT_UNIXINFO_V0 \ -{ \ - { \ - 0x9c54e310, 0xa955, 0x4885, \ - { 0xbd, 0x31 }, \ - { 0x78, 0x78, \ - 0x71, 0x47, 0xdf, 0xa6 } \ - }, 0x00 \ -} - #define SYNT_NTSVCS_V1 \ { \ { \ diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c index 6c2b4f4ea71..7cbaa4e3c99 100644 --- a/source/rpc_parse/parse_samr.c +++ b/source/rpc_parse/parse_samr.c @@ -5031,7 +5031,7 @@ inits a SAMR_Q_QUERY_USERINFO structure. ********************************************************************/ void init_samr_q_query_userinfo(SAMR_Q_QUERY_USERINFO * q_u, - POLICY_HND *hnd, uint16 switch_value) + const POLICY_HND *hnd, uint16 switch_value) { DEBUG(5, ("init_samr_q_query_userinfo\n")); @@ -6541,7 +6541,7 @@ inits a SAMR_Q_SET_USERINFO structure. ********************************************************************/ void init_samr_q_set_userinfo(SAMR_Q_SET_USERINFO * q_u, - POLICY_HND *hnd, DATA_BLOB *sess_key, + const POLICY_HND *hnd, DATA_BLOB *sess_key, uint16 switch_value, void *info) { DEBUG(5, ("init_samr_q_set_userinfo\n")); @@ -6615,7 +6615,7 @@ inits a SAMR_Q_SET_USERINFO2 structure. ********************************************************************/ void init_samr_q_set_userinfo2(SAMR_Q_SET_USERINFO2 * q_u, - POLICY_HND *hnd, DATA_BLOB *sess_key, + const POLICY_HND *hnd, DATA_BLOB *sess_key, uint16 switch_value, SAM_USERINFO_CTR * ctr) { DEBUG(5, ("init_samr_q_set_userinfo2\n")); diff --git a/source/rpc_server/srv_dfs.c b/source/rpc_server/srv_dfs.c index 42be7c5a357..44a9c06a3ca 100644 --- a/source/rpc_server/srv_dfs.c +++ b/source/rpc_server/srv_dfs.c @@ -1,177 +1,602 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines for Dfs - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Shirish Kalele 2000, - * Copyright (C) Jeremy Allison 2001, - * Copyright (C) Jim McDonough 2003. - * - * 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. +/* + * Unix SMB/CIFS implementation. + * server auto-generated by pidl. DO NOT MODIFY! */ -/* This is the interface to the dfs pipe. */ - #include "includes.h" #include "nterr.h" #undef DBGC_CLASS -#define DBGC_CLASS DBGC_MSDFS +#define DBGC_CLASS DBGC_RPC -/********************************************************************** - api_dfs_exist - **********************************************************************/ +/****************************************************************** + api_dfs_GetManagerVersion + *****************************************************************/ -static BOOL api_dfs_exist(pipes_struct *p) +static BOOL api_dfs_GetManagerVersion(pipes_struct *p) { - DFS_Q_DFS_EXIST q_u; - DFS_R_DFS_EXIST r_u; + NETDFS_Q_DFS_GETMANAGERVERSION q_u; + NETDFS_R_DFS_GETMANAGERVERSION r_u; prs_struct *data = &p->in_data.data; prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_GetManagerVersion("", &q_u, data, 0)) + return False; + + _dfs_GetManagerVersion(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_GetManagerVersion("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_Add + *****************************************************************/ - if(!dfs_io_q_dfs_exist("", &q_u, data, 0)) +static BOOL api_dfs_Add(pipes_struct *p) +{ + NETDFS_Q_DFS_ADD q_u; + NETDFS_R_DFS_ADD r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_Add("", &q_u, data, 0)) return False; - r_u.status = _dfs_exist(p, &q_u, &r_u); + r_u.status = _dfs_Add(p, &q_u, &r_u); - if (!dfs_io_r_dfs_exist("", &r_u, rdata, 0)) + if (!netdfs_io_r_dfs_Add("", &r_u, rdata, 0)) return False; + + return True; +} +/****************************************************************** + api_dfs_Remove + *****************************************************************/ +static BOOL api_dfs_Remove(pipes_struct *p) +{ + NETDFS_Q_DFS_REMOVE q_u; + NETDFS_R_DFS_REMOVE r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_Remove("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_Remove(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_Remove("", &r_u, rdata, 0)) + return False; + return True; } +/****************************************************************** + api_dfs_SetInfo + *****************************************************************/ -/***************************************************************** - api_dfs_add +static BOOL api_dfs_SetInfo(pipes_struct *p) +{ + NETDFS_Q_DFS_SETINFO q_u; + NETDFS_R_DFS_SETINFO r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_SetInfo("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_SetInfo(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_SetInfo("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_GetInfo *****************************************************************/ -static BOOL api_dfs_add(pipes_struct *p) +static BOOL api_dfs_GetInfo(pipes_struct *p) { - DFS_Q_DFS_ADD q_u; - DFS_R_DFS_ADD r_u; + NETDFS_Q_DFS_GETINFO q_u; + NETDFS_R_DFS_GETINFO r_u; prs_struct *data = &p->in_data.data; prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_GetInfo("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_GetInfo(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_GetInfo("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_Enum + *****************************************************************/ +static BOOL api_dfs_Enum(pipes_struct *p) +{ + NETDFS_Q_DFS_ENUM q_u; + NETDFS_R_DFS_ENUM r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - if(!dfs_io_q_dfs_add("", &q_u, data, 0)) + if (!netdfs_io_q_dfs_Enum("", &q_u, data, 0)) return False; - r_u.status = _dfs_add(p, &q_u, &r_u); + r_u.status = _dfs_Enum(p, &q_u, &r_u); - if (!dfs_io_r_dfs_add("", &r_u, rdata, 0)) + if (!netdfs_io_r_dfs_Enum("", &r_u, rdata, 0)) return False; return True; } +/****************************************************************** + api_dfs_Rename + *****************************************************************/ -/***************************************************************** - api_dfs_remove +static BOOL api_dfs_Rename(pipes_struct *p) +{ + NETDFS_Q_DFS_RENAME q_u; + NETDFS_R_DFS_RENAME r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_Rename("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_Rename(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_Rename("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_Move *****************************************************************/ -static BOOL api_dfs_remove(pipes_struct *p) +static BOOL api_dfs_Move(pipes_struct *p) { - DFS_Q_DFS_REMOVE q_u; - DFS_R_DFS_REMOVE r_u; + NETDFS_Q_DFS_MOVE q_u; + NETDFS_R_DFS_MOVE r_u; prs_struct *data = &p->in_data.data; prs_struct *rdata = &p->out_data.rdata; ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - if(!dfs_io_q_dfs_remove("", &q_u, data, 0)) + if (!netdfs_io_q_dfs_Move("", &q_u, data, 0)) return False; - r_u.status = _dfs_remove(p, &q_u, &r_u); + r_u.status = _dfs_Move(p, &q_u, &r_u); - if (!dfs_io_r_dfs_remove("", &r_u, rdata, 0)) + if (!netdfs_io_r_dfs_Move("", &r_u, rdata, 0)) return False; return True; } +/****************************************************************** + api_dfs_ManagerGetConfigInfo + *****************************************************************/ -/******************************************************************* - api_dfs_get_info - *******************************************************************/ +static BOOL api_dfs_ManagerGetConfigInfo(pipes_struct *p) +{ + NETDFS_Q_DFS_MANAGERGETCONFIGINFO q_u; + NETDFS_R_DFS_MANAGERGETCONFIGINFO r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_ManagerGetConfigInfo("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_ManagerGetConfigInfo(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_ManagerGetConfigInfo("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_ManagerSendSiteInfo + *****************************************************************/ -static BOOL api_dfs_get_info(pipes_struct *p) +static BOOL api_dfs_ManagerSendSiteInfo(pipes_struct *p) { - DFS_Q_DFS_GET_INFO q_u; - DFS_R_DFS_GET_INFO r_u; + NETDFS_Q_DFS_MANAGERSENDSITEINFO q_u; + NETDFS_R_DFS_MANAGERSENDSITEINFO r_u; prs_struct *data = &p->in_data.data; prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_ManagerSendSiteInfo("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_ManagerSendSiteInfo(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_ManagerSendSiteInfo("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_AddFtRoot + *****************************************************************/ +static BOOL api_dfs_AddFtRoot(pipes_struct *p) +{ + NETDFS_Q_DFS_ADDFTROOT q_u; + NETDFS_R_DFS_ADDFTROOT r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - if(!dfs_io_q_dfs_get_info("", &q_u, data, 0)) + if (!netdfs_io_q_dfs_AddFtRoot("", &q_u, data, 0)) return False; - r_u.status = _dfs_get_info(p, &q_u, &r_u); + r_u.status = _dfs_AddFtRoot(p, &q_u, &r_u); - if(!dfs_io_r_dfs_get_info("", &r_u, rdata, 0)) + if (!netdfs_io_r_dfs_AddFtRoot("", &r_u, rdata, 0)) return False; + + return True; +} +/****************************************************************** + api_dfs_RemoveFtRoot + *****************************************************************/ +static BOOL api_dfs_RemoveFtRoot(pipes_struct *p) +{ + NETDFS_Q_DFS_REMOVEFTROOT q_u; + NETDFS_R_DFS_REMOVEFTROOT r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_RemoveFtRoot("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_RemoveFtRoot(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_RemoveFtRoot("", &r_u, rdata, 0)) + return False; + return True; } +/****************************************************************** + api_dfs_AddStdRoot + *****************************************************************/ -/******************************************************************* - api_dfs_enum - *******************************************************************/ +static BOOL api_dfs_AddStdRoot(pipes_struct *p) +{ + NETDFS_Q_DFS_ADDSTDROOT q_u; + NETDFS_R_DFS_ADDSTDROOT r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_AddStdRoot("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_AddStdRoot(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_AddStdRoot("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_RemoveStdRoot + *****************************************************************/ -static BOOL api_dfs_enum(pipes_struct *p) +static BOOL api_dfs_RemoveStdRoot(pipes_struct *p) { - DFS_Q_DFS_ENUM q_u; - DFS_R_DFS_ENUM r_u; + NETDFS_Q_DFS_REMOVESTDROOT q_u; + NETDFS_R_DFS_REMOVESTDROOT r_u; prs_struct *data = &p->in_data.data; prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_RemoveStdRoot("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_RemoveStdRoot(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_RemoveStdRoot("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_ManagerInitialize + *****************************************************************/ +static BOOL api_dfs_ManagerInitialize(pipes_struct *p) +{ + NETDFS_Q_DFS_MANAGERINITIALIZE q_u; + NETDFS_R_DFS_MANAGERINITIALIZE r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_ManagerInitialize("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_ManagerInitialize(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_ManagerInitialize("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_AddStdRootForced + *****************************************************************/ - if(!dfs_io_q_dfs_enum("", &q_u, data, 0)) +static BOOL api_dfs_AddStdRootForced(pipes_struct *p) +{ + NETDFS_Q_DFS_ADDSTDROOTFORCED q_u; + NETDFS_R_DFS_ADDSTDROOTFORCED r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_AddStdRootForced("", &q_u, data, 0)) return False; - r_u.status = _dfs_enum(p, &q_u, &r_u); + r_u.status = _dfs_AddStdRootForced(p, &q_u, &r_u); - if(!dfs_io_r_dfs_enum("", &r_u, rdata, 0)) + if (!netdfs_io_r_dfs_AddStdRootForced("", &r_u, rdata, 0)) return False; + + return True; +} +/****************************************************************** + api_dfs_GetDcAddress + *****************************************************************/ +static BOOL api_dfs_GetDcAddress(pipes_struct *p) +{ + NETDFS_Q_DFS_GETDCADDRESS q_u; + NETDFS_R_DFS_GETDCADDRESS r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_GetDcAddress("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_GetDcAddress(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_GetDcAddress("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_SetDcAddress + *****************************************************************/ + +static BOOL api_dfs_SetDcAddress(pipes_struct *p) +{ + NETDFS_Q_DFS_SETDCADDRESS q_u; + NETDFS_R_DFS_SETDCADDRESS r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_SetDcAddress("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_SetDcAddress(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_SetDcAddress("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_FlushFtTable + *****************************************************************/ + +static BOOL api_dfs_FlushFtTable(pipes_struct *p) +{ + NETDFS_Q_DFS_FLUSHFTTABLE q_u; + NETDFS_R_DFS_FLUSHFTTABLE r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_FlushFtTable("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_FlushFtTable(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_FlushFtTable("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_Add2 + *****************************************************************/ + +static BOOL api_dfs_Add2(pipes_struct *p) +{ + NETDFS_Q_DFS_ADD2 q_u; + NETDFS_R_DFS_ADD2 r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_Add2("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_Add2(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_Add2("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_Remove2 + *****************************************************************/ + +static BOOL api_dfs_Remove2(pipes_struct *p) +{ + NETDFS_Q_DFS_REMOVE2 q_u; + NETDFS_R_DFS_REMOVE2 r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_Remove2("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_Remove2(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_Remove2("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_EnumEx + *****************************************************************/ + +static BOOL api_dfs_EnumEx(pipes_struct *p) +{ + NETDFS_Q_DFS_ENUMEX q_u; + NETDFS_R_DFS_ENUMEX r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_EnumEx("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_EnumEx(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_EnumEx("", &r_u, rdata, 0)) + return False; + + return True; +} +/****************************************************************** + api_dfs_SetInfo2 + *****************************************************************/ + +static BOOL api_dfs_SetInfo2(pipes_struct *p) +{ + NETDFS_Q_DFS_SETINFO2 q_u; + NETDFS_R_DFS_SETINFO2 r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!netdfs_io_q_dfs_SetInfo2("", &q_u, data, 0)) + return False; + + r_u.status = _dfs_SetInfo2(p, &q_u, &r_u); + + if (!netdfs_io_r_dfs_SetInfo2("", &r_u, rdata, 0)) + return False; + return True; } -/******************************************************************* -\pipe\netdfs commands -********************************************************************/ -static struct api_struct api_netdfs_cmds[] = +/* Tables */ +static struct api_struct api_netdfs_cmds[] = { - {"DFS_EXIST", DFS_EXIST, api_dfs_exist }, - {"DFS_ADD", DFS_ADD, api_dfs_add }, - {"DFS_REMOVE", DFS_REMOVE, api_dfs_remove }, - {"DFS_GET_INFO", DFS_GET_INFO, api_dfs_get_info }, - {"DFS_ENUM", DFS_ENUM, api_dfs_enum } + {"DFS_GETMANAGERVERSION", DFS_GETMANAGERVERSION, api_dfs_GetManagerVersion}, + {"DFS_ADD", DFS_ADD, api_dfs_Add}, + {"DFS_REMOVE", DFS_REMOVE, api_dfs_Remove}, + {"DFS_SETINFO", DFS_SETINFO, api_dfs_SetInfo}, + {"DFS_GETINFO", DFS_GETINFO, api_dfs_GetInfo}, + {"DFS_ENUM", DFS_ENUM, api_dfs_Enum}, + {"DFS_RENAME", DFS_RENAME, api_dfs_Rename}, + {"DFS_MOVE", DFS_MOVE, api_dfs_Move}, + {"DFS_MANAGERGETCONFIGINFO", DFS_MANAGERGETCONFIGINFO, api_dfs_ManagerGetConfigInfo}, + {"DFS_MANAGERSENDSITEINFO", DFS_MANAGERSENDSITEINFO, api_dfs_ManagerSendSiteInfo}, + {"DFS_ADDFTROOT", DFS_ADDFTROOT, api_dfs_AddFtRoot}, + {"DFS_REMOVEFTROOT", DFS_REMOVEFTROOT, api_dfs_RemoveFtRoot}, + {"DFS_ADDSTDROOT", DFS_ADDSTDROOT, api_dfs_AddStdRoot}, + {"DFS_REMOVESTDROOT", DFS_REMOVESTDROOT, api_dfs_RemoveStdRoot}, + {"DFS_MANAGERINITIALIZE", DFS_MANAGERINITIALIZE, api_dfs_ManagerInitialize}, + {"DFS_ADDSTDROOTFORCED", DFS_ADDSTDROOTFORCED, api_dfs_AddStdRootForced}, + {"DFS_GETDCADDRESS", DFS_GETDCADDRESS, api_dfs_GetDcAddress}, + {"DFS_SETDCADDRESS", DFS_SETDCADDRESS, api_dfs_SetDcAddress}, + {"DFS_FLUSHFTTABLE", DFS_FLUSHFTTABLE, api_dfs_FlushFtTable}, + {"DFS_ADD2", DFS_ADD2, api_dfs_Add2}, + {"DFS_REMOVE2", DFS_REMOVE2, api_dfs_Remove2}, + {"DFS_ENUMEX", DFS_ENUMEX, api_dfs_EnumEx}, + {"DFS_SETINFO2", DFS_SETINFO2, api_dfs_SetInfo2}, }; -void netdfs_get_pipe_fns( struct api_struct **fns, int *n_fns ) +void netdfs_get_pipe_fns(struct api_struct **fns, int *n_fns) { *fns = api_netdfs_cmds; *n_fns = sizeof(api_netdfs_cmds) / sizeof(struct api_struct); } -NTSTATUS rpc_dfs_init(void) +NTSTATUS rpc_netdfs_init(void) { - return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "netdfs", "netdfs", api_netdfs_cmds, - sizeof(api_netdfs_cmds) / sizeof(struct api_struct)); + return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "netdfs", "netdfs", api_netdfs_cmds, sizeof(api_netdfs_cmds) / sizeof(struct api_struct)); } diff --git a/source/rpc_server/srv_dfs_nt.c b/source/rpc_server/srv_dfs_nt.c index 63e4d4e9b7c..f04d8c37c3d 100644 --- a/source/rpc_server/srv_dfs_nt.c +++ b/source/rpc_server/srv_dfs_nt.c @@ -1,10 +1,9 @@ /* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines for Dfs - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Shirish Kalele 2000. - * Copyright (C) Jeremy Allison 2001. + * Copyright (C) Shirish Kalele 2000. + * Copyright (C) Jeremy Allison 2001. + * Copyright (C) Jelmer Vernooij 2005. * * 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 @@ -24,7 +23,6 @@ /* This is the implementation of the dfs pipe. */ #include "includes.h" -#include "nterr.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_MSDFS @@ -32,7 +30,7 @@ /* This function does not return a WERROR or NTSTATUS code but rather 1 if dfs exists, or 0 otherwise. */ -uint32 _dfs_exist(pipes_struct *p, DFS_Q_DFS_EXIST *q_u, DFS_R_DFS_EXIST *r_u) +uint32 _dfs_GetManagerVersion(pipes_struct *p, NETDFS_Q_DFS_GETMANAGERVERSION *q_u, NETDFS_R_DFS_GETMANAGERVERSION *r_u) { if(lp_host_msdfs()) return 1; @@ -40,7 +38,7 @@ uint32 _dfs_exist(pipes_struct *p, DFS_Q_DFS_EXIST *q_u, DFS_R_DFS_EXIST *r_u) return 0; } -WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u) +WERROR _dfs_Add(pipes_struct *p, NETDFS_Q_DFS_ADD* q_u, NETDFS_R_DFS_ADD *r_u) { struct current_user user; struct junction_map jn; @@ -57,9 +55,9 @@ WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u) return WERR_ACCESS_DENIED; } - unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1); - unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1); - unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1); + unistr2_to_ascii(dfspath, &q_u->path, sizeof(dfspath)-1); + unistr2_to_ascii(servername, &q_u->server, sizeof(servername)-1); + unistr2_to_ascii(sharename, &q_u->share, sizeof(sharename)-1); DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n", dfspath, servername, sharename)); @@ -103,8 +101,8 @@ WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u) return WERR_OK; } -WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, - DFS_R_DFS_REMOVE *r_u) +WERROR _dfs_Remove(pipes_struct *p, NETDFS_Q_DFS_REMOVE *q_u, + NETDFS_R_DFS_REMOVE *r_u) { struct current_user user; struct junction_map jn; @@ -120,16 +118,16 @@ WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, return WERR_ACCESS_DENIED; } - unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1); - if(q_u->ptr_ServerName) { - unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1); + unistr2_to_ascii(dfspath, &q_u->path, sizeof(dfspath)-1); + if(q_u->ptr0_server) { + unistr2_to_ascii(servername, &q_u->server, sizeof(servername)-1); } - if(q_u->ptr_ShareName) { - unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1); + if(q_u->ptr0_share) { + unistr2_to_ascii(sharename, &q_u->share, sizeof(sharename)-1); } - if(q_u->ptr_ServerName && q_u->ptr_ShareName) { + if(q_u->ptr0_server && q_u->ptr0_share) { pstrcpy(altpath, servername); pstrcat(altpath, "\\"); pstrcat(altpath, sharename); @@ -144,7 +142,7 @@ WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, } /* if no server-share pair given, remove the msdfs link completely */ - if(!q_u->ptr_ServerName && !q_u->ptr_ShareName) { + if(!q_u->ptr0_server && !q_u->ptr0_share) { if(!remove_msdfs_link(&jn)) { vfs_ChDir(p->conn,p->conn->connectpath); return WERR_DFS_NO_SUCH_VOL; @@ -189,167 +187,164 @@ WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, return WERR_OK; } -static BOOL init_reply_dfs_info_1(struct junction_map* j, DFS_INFO_1* dfs1, int num_j) +static BOOL init_reply_dfs_info_1(struct junction_map* j, NETDFS_DFS_INFO1* dfs1) { - int i=0; - for(i=0;iptr0_path = 1; + slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), + j->service_name, j->volume_name); + DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",str)); + init_unistr2(&dfs1->path,str,UNI_STR_TERMINATE); return True; } -static BOOL init_reply_dfs_info_2(struct junction_map* j, DFS_INFO_2* dfs2, int num_j) +static BOOL init_reply_dfs_info_2(struct junction_map* j, NETDFS_DFS_INFO2* dfs2) { - int i=0; - for(i=0;iptr0_path = 1; + slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), + j->service_name, j->volume_name); + init_unistr2(&dfs2->path, str, UNI_STR_TERMINATE); + dfs2->ptr0_comment = 0; + dfs2->state = 1; /* set up state of dfs junction as OK */ + dfs2->num_stores = j->referral_count; return True; } -static BOOL init_reply_dfs_info_3(TALLOC_CTX *ctx, struct junction_map* j, DFS_INFO_3* dfs3, int num_j) +static BOOL init_reply_dfs_info_3(TALLOC_CTX *ctx, struct junction_map* j, NETDFS_DFS_INFO3* dfs3) { - int i=0,ii=0; - for(i=0;ialternate_path); - trim_char(path,'\\','\0'); - p = strrchr_m(path,'\\'); - if(p==NULL) { - DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path)); - continue; - } - *p = '\0'; - DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1)); - stor->state = 2; /* set all storages as ONLINE */ - init_unistr2(&stor->servername, path, UNI_STR_TERMINATE); - init_unistr2(&stor->sharename, p+1, UNI_STR_TERMINATE); - stor->ptr_servername = stor->ptr_sharename = 1; + int ii; + pstring str; + dfs3->ptr0_path = 1; + if (j->volume_name[0] == '\0') + slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s", + global_myname(), j->service_name); + else + slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), + j->service_name, j->volume_name); + + init_unistr2(&dfs3->path, str, UNI_STR_TERMINATE); + dfs3->ptr0_comment = 1; + init_unistr2(&dfs3->comment, "", UNI_STR_TERMINATE); + dfs3->state = 1; + dfs3->num_stores = dfs3->size_stores = j->referral_count; + dfs3->ptr0_stores = 1; + + /* also enumerate the stores */ + dfs3->stores = TALLOC_ARRAY(ctx, NETDFS_DFS_STORAGEINFO, j->referral_count); + if (!dfs3->stores) + return False; + + memset(dfs3->stores, '\0', j->referral_count * sizeof(NETDFS_DFS_STORAGEINFO)); + + for(ii=0;iireferral_count;ii++) { + char* p; + pstring path; + NETDFS_DFS_STORAGEINFO* stor = &(dfs3->stores[ii]); + struct referral* ref = &(j->referral_list[ii]); + + pstrcpy(path, ref->alternate_path); + trim_char(path,'\\','\0'); + p = strrchr_m(path,'\\'); + if(p==NULL) { + DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path)); + continue; } + *p = '\0'; + DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1)); + stor->state = 2; /* set all stores as ONLINE */ + init_unistr2(&stor->server, path, UNI_STR_TERMINATE); + init_unistr2(&stor->share, p+1, UNI_STR_TERMINATE); + stor->ptr0_server = stor->ptr0_share = 1; } return True; } -static WERROR init_reply_dfs_ctr(TALLOC_CTX *ctx, uint32 level, - DFS_INFO_CTR* ctr, struct junction_map* jn, - int num_jn) +WERROR _dfs_Enum(pipes_struct *p, NETDFS_Q_DFS_ENUM *q_u, NETDFS_R_DFS_ENUM *r_u) { - /* do the levels */ - switch(level) { + uint32 level = q_u->level; + struct junction_map jn[MAX_MSDFS_JUNCTIONS]; + int num_jn = 0; + int i; + + num_jn = enum_msdfs_links(p->mem_ctx, jn, ARRAY_SIZE(jn)); + vfs_ChDir(p->conn,p->conn->connectpath); + + DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n", num_jn, level)); + + r_u->ptr0_info = q_u->ptr0_info; + r_u->ptr0_total = q_u->ptr0_total; + r_u->total = num_jn; + + r_u->info = q_u->info; + + /* Create the return array */ + switch (level) { case 1: - { - DFS_INFO_1* dfs1; - dfs1 = TALLOC_ARRAY(ctx, DFS_INFO_1, num_jn); - if (!dfs1) + if ((r_u->info.e.u.info1.s = TALLOC_ARRAY(p->mem_ctx, NETDFS_DFS_INFO1, num_jn)) == NULL) { return WERR_NOMEM; - init_reply_dfs_info_1(jn, dfs1, num_jn); - ctr->dfs.info1 = dfs1; - break; } + r_u->info.e.u.info1.count = num_jn; + r_u->info.e.u.info1.ptr0_s = 1; + r_u->info.e.u.info1.size_s = num_jn; + break; case 2: - { - DFS_INFO_2* dfs2; - dfs2 = TALLOC_ARRAY(ctx, DFS_INFO_2, num_jn); - if (!dfs2) + if ((r_u->info.e.u.info2.s = TALLOC_ARRAY(p->mem_ctx, NETDFS_DFS_INFO2, num_jn)) == NULL) { return WERR_NOMEM; - init_reply_dfs_info_2(jn, dfs2, num_jn); - ctr->dfs.info2 = dfs2; - break; } + r_u->info.e.u.info2.count = num_jn; + r_u->info.e.u.info2.ptr0_s = 1; + r_u->info.e.u.info2.size_s = num_jn; + break; case 3: - { - DFS_INFO_3* dfs3; - dfs3 = TALLOC_ARRAY(ctx, DFS_INFO_3, num_jn); - if (!dfs3) + if ((r_u->info.e.u.info3.s = TALLOC_ARRAY(p->mem_ctx, NETDFS_DFS_INFO3, num_jn)) == NULL) { return WERR_NOMEM; - init_reply_dfs_info_3(ctx, jn, dfs3, num_jn); - ctr->dfs.info3 = dfs3; + } + r_u->info.e.u.info3.count = num_jn; + r_u->info.e.u.info3.ptr0_s = 1; + r_u->info.e.u.info3.size_s = num_jn; break; + case 4: + if ((r_u->info.e.u.info4.s = TALLOC_ARRAY(p->mem_ctx, NETDFS_DFS_INFO4, num_jn)) == NULL) { + return WERR_NOMEM; } + r_u->info.e.u.info4.count = num_jn; + r_u->info.e.u.info4.ptr0_s = 1; + r_u->info.e.u.info4.size_s = num_jn; + break; default: return WERR_INVALID_PARAM; } - return WERR_OK; -} - -WERROR _dfs_enum(pipes_struct *p, DFS_Q_DFS_ENUM *q_u, DFS_R_DFS_ENUM *r_u) -{ - uint32 level = q_u->level; - struct junction_map jn[MAX_MSDFS_JUNCTIONS]; - int num_jn = 0; - - num_jn = enum_msdfs_links(p->mem_ctx, jn, ARRAY_SIZE(jn)); - vfs_ChDir(p->conn,p->conn->connectpath); - - DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n", num_jn, level)); - r_u->ptr_buffer = level; - r_u->level = r_u->level2 = level; - r_u->ptr_num_entries = r_u->ptr_num_entries2 = 1; - r_u->num_entries = r_u->num_entries2 = num_jn; - r_u->reshnd.ptr_hnd = 1; - r_u->reshnd.handle = num_jn; - - r_u->ctr = TALLOC_P(p->mem_ctx, DFS_INFO_CTR); - if (!r_u->ctr) - return WERR_NOMEM; - ZERO_STRUCTP(r_u->ctr); - r_u->ctr->switch_value = level; - r_u->ctr->num_entries = num_jn; - r_u->ctr->ptr_dfs_ctr = 1; + for (i = 0; i < num_jn; i++) { + switch (level) { + case 1: + init_reply_dfs_info_1(&jn[i], &r_u->info.e.u.info1.s[i]); + break; + case 2: + init_reply_dfs_info_2(&jn[i], &r_u->info.e.u.info2.s[i]); + break; + case 3: + init_reply_dfs_info_3(p->mem_ctx, &jn[i], &r_u->info.e.u.info3.s[i]); + break; + default: + return WERR_INVALID_PARAM; + } + } - r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, r_u->ctr, jn, num_jn); + r_u->status = WERR_OK; return r_u->status; } -WERROR _dfs_get_info(pipes_struct *p, DFS_Q_DFS_GET_INFO *q_u, - DFS_R_DFS_GET_INFO *r_u) +WERROR _dfs_GetInfo(pipes_struct *p, NETDFS_Q_DFS_GETINFO *q_u, + NETDFS_R_DFS_GETINFO *r_u) { - UNISTR2* uni_path = &q_u->uni_path; + UNISTR2* uni_path = &q_u->path; uint32 level = q_u->level; int consumedcnt = sizeof(pstring); pstring path; + BOOL ret; struct junction_map jn; unistr2_to_ascii(path, uni_path, sizeof(path)-1); @@ -363,9 +358,130 @@ WERROR _dfs_get_info(pipes_struct *p, DFS_Q_DFS_GET_INFO *q_u, } vfs_ChDir(p->conn,p->conn->connectpath); - r_u->level = level; - r_u->ptr_ctr = 1; - r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, &r_u->ctr, &jn, 1); + r_u->info.switch_value = level; + r_u->info.ptr0 = 1; + r_u->status = WERR_OK; + + switch (level) { + case 1: ret = init_reply_dfs_info_1(&jn, &r_u->info.u.info1); break; + case 2: ret = init_reply_dfs_info_2(&jn, &r_u->info.u.info2); break; + case 3: ret = init_reply_dfs_info_3(p->mem_ctx, &jn, &r_u->info.u.info3); break; + default: + ret = False; + break; + } + + if (!ret) + r_u->status = WERR_INVALID_PARAM; return r_u->status; } + +WERROR _dfs_SetInfo(pipes_struct *p, NETDFS_Q_DFS_SETINFO *q_u, NETDFS_R_DFS_SETINFO *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Rename(pipes_struct *p, NETDFS_Q_DFS_RENAME *q_u, NETDFS_R_DFS_RENAME *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Move(pipes_struct *p, NETDFS_Q_DFS_MOVE *q_u, NETDFS_R_DFS_MOVE *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerGetConfigInfo(pipes_struct *p, NETDFS_Q_DFS_MANAGERGETCONFIGINFO *q_u, NETDFS_R_DFS_MANAGERGETCONFIGINFO *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerSendSiteInfo(pipes_struct *p, NETDFS_Q_DFS_MANAGERSENDSITEINFO *q_u, NETDFS_R_DFS_MANAGERSENDSITEINFO *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddFtRoot(pipes_struct *p, NETDFS_Q_DFS_ADDFTROOT *q_u, NETDFS_R_DFS_ADDFTROOT *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_RemoveFtRoot(pipes_struct *p, NETDFS_Q_DFS_REMOVEFTROOT *q_u, NETDFS_R_DFS_REMOVEFTROOT *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddStdRoot(pipes_struct *p, NETDFS_Q_DFS_ADDSTDROOT *q_u, NETDFS_R_DFS_ADDSTDROOT *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_RemoveStdRoot(pipes_struct *p, NETDFS_Q_DFS_REMOVESTDROOT *q_u, NETDFS_R_DFS_REMOVESTDROOT *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerInitialize(pipes_struct *p, NETDFS_Q_DFS_MANAGERINITIALIZE *q_u, NETDFS_R_DFS_MANAGERINITIALIZE *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddStdRootForced(pipes_struct *p, NETDFS_Q_DFS_ADDSTDROOTFORCED *q_u, NETDFS_R_DFS_ADDSTDROOTFORCED *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_GetDcAddress(pipes_struct *p, NETDFS_Q_DFS_GETDCADDRESS *q_u, NETDFS_R_DFS_GETDCADDRESS *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_SetDcAddress(pipes_struct *p, NETDFS_Q_DFS_SETDCADDRESS *q_u, NETDFS_R_DFS_SETDCADDRESS *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_FlushFtTable(pipes_struct *p, NETDFS_Q_DFS_FLUSHFTTABLE *q_u, NETDFS_R_DFS_FLUSHFTTABLE *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Add2(pipes_struct *p, NETDFS_Q_DFS_ADD2 *q_u, NETDFS_R_DFS_ADD2 *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Remove2(pipes_struct *p, NETDFS_Q_DFS_REMOVE2 *q_u, NETDFS_R_DFS_REMOVE2 *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_EnumEx(pipes_struct *p, NETDFS_Q_DFS_ENUMEX *q_u, NETDFS_R_DFS_ENUMEX *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_SetInfo2(pipes_struct *p, NETDFS_Q_DFS_SETINFO2 *q_u, NETDFS_R_DFS_SETINFO2 *r_u) +{ + /* FIXME: Implement your code here */ + return WERR_NOT_SUPPORTED; +} + diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c index f48f3e863a8..c93107cec41 100644 --- a/source/rpc_server/srv_lsa_nt.c +++ b/source/rpc_server/srv_lsa_nt.c @@ -9,6 +9,7 @@ * Copyright (C) Jim McDonough 2002, * Copyright (C) Simo Sorce 2003. * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Volker Lendecke 2005. * * 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 @@ -102,9 +103,7 @@ static int init_dom_ref(DOM_R_REF *ref, const char *dom_name, DOM_SID *dom_sid) if (dom_name != NULL) { for (num = 0; num < ref->num_ref_doms_1; num++) { - fstring domname; - rpcstr_pull(domname, ref->ref_dom[num].uni_dom_name.buffer, sizeof(domname), -1, 0); - if (strequal(domname, dom_name)) + if (sid_equal(dom_sid, &ref->ref_dom[num].ref_dom.sid)) return num; } } else { @@ -159,8 +158,8 @@ static int init_lsa_rid2s(TALLOC_CTX *mem_ctx, /* Split name into domain and user component */ - if (rpcstr_pull_unistr2_talloc(mem_ctx, &full_name, - &name[i]) < 0) { + full_name = rpcstr_pull_unistr2_talloc(mem_ctx, &name[i]); + if (full_name == NULL) { DEBUG(0, ("pull_ucs2_talloc failed\n")); return 0; } @@ -226,87 +225,6 @@ static void init_reply_lookup_names(LSA_R_LOOKUP_NAMES *r_l, r_l->mapped_count = mapped_count; } -/*************************************************************************** - Init lsa_trans_names. - ***************************************************************************/ - -static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *trn, - int num_entries, DOM_SID2 *sid, - uint32 *mapped_count) -{ - int i; - int total = 0; - *mapped_count = 0; - - /* Allocate memory for list of names */ - - if (num_entries > 0) { - if (!(trn->name = TALLOC_ARRAY(ctx, LSA_TRANS_NAME, num_entries))) { - DEBUG(0, ("init_lsa_trans_names(): out of memory\n")); - return; - } - - if (!(trn->uni_name = TALLOC_ARRAY(ctx, UNISTR2, num_entries))) { - DEBUG(0, ("init_lsa_trans_names(): out of memory\n")); - return; - } - } - - become_root(); /* Need root to get to passdb to for local sids */ - - for (i = 0; i < num_entries; i++) { - BOOL status = False; - DOM_SID find_sid = sid[i].sid; - uint32 rid = 0xffffffff; - int dom_idx = -1; - const char *name, *domain; - enum SID_NAME_USE type = SID_NAME_UNKNOWN; - - DEBUG(5, ("init_lsa_trans_names: looking up sid %s\n", - sid_string_static(&find_sid))); - - /* Lookup sid from winbindd */ - - status = lookup_sid(ctx, &find_sid, &domain, &name, &type); - - DEBUG(5, ("init_lsa_trans_names: %s\n", status ? "found" : - "not found")); - - if (!status) { - type = SID_NAME_UNKNOWN; - domain = talloc_strdup(ctx, ""); - name = talloc_strdup(ctx, - sid_string_static(&find_sid)); - dom_idx = -1; - - DEBUG(10,("init_lsa_trans_names: added unknown user " - "'%s' to referenced list.\n", name )); - } else { - (*mapped_count)++; - /* Store domain sid in ref array */ - if (find_sid.num_auths == 5) { - sid_split_rid(&find_sid, &rid); - } - dom_idx = init_dom_ref(ref, domain, &find_sid); - - DEBUG(10,("init_lsa_trans_names: added %s '%s\\%s' " - "(%d) to referenced list.\n", - sid_type_lookup(type), domain, name, type)); - - } - - init_lsa_trans_name(&trn->name[total], &trn->uni_name[total], - type, name, dom_idx); - total++; - } - - unbecome_root(); - - trn->num_entries = total; - trn->ptr_trans_names = 1; - trn->num_entries2 = total; -} - /*************************************************************************** Init_reply_lookup_sids. ***************************************************************************/ @@ -315,7 +233,7 @@ static void init_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l, DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *names, uint32 mapped_count) { - r_l->ptr_dom_ref = 1; + r_l->ptr_dom_ref = ref ? 1 : 0; r_l->dom_ref = ref; r_l->names = names; r_l->mapped_count = mapped_count; @@ -496,10 +414,12 @@ NTSTATUS _lsa_open_policy(pipes_struct *p, LSA_Q_OPEN_POL *q_u, LSA_R_OPEN_POL * ufff, done :) mimir ***************************************************************************/ -NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_ENUM_TRUST_DOM *r_u) +NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, + LSA_R_ENUM_TRUST_DOM *r_u) { struct lsa_info *info; - uint32 enum_context = q_u->enum_context; + uint32 next_idx; + struct trustdom_info **domains; /* * preferred length is set to 5 as a "our" preferred length @@ -507,10 +427,11 @@ NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_E * update (20.08.2002): it's not preferred length, but preferred size! * it needs further investigation how to optimally choose this value */ - uint32 max_num_domains = q_u->preferred_len < 5 ? q_u->preferred_len : 10; - TRUSTDOM **trust_doms; + uint32 max_num_domains = + q_u->preferred_len < 5 ? q_u->preferred_len : 10; uint32 num_domains; NTSTATUS nt_status; + uint32 num_thistime; if (!find_policy_by_hnd(p, &q_u->pol, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; @@ -519,19 +440,34 @@ NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_E if (!(info->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - nt_status = secrets_get_trusted_domains(p->mem_ctx, (int *)&enum_context, max_num_domains, (int *)&num_domains, &trust_doms); + nt_status = secrets_trusted_domains(p->mem_ctx, &num_domains, + &domains); - if (!NT_STATUS_IS_OK(nt_status) && - !NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES) && - !NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES)) { + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; - } else { - r_u->status = nt_status; } + if (q_u->enum_context < num_domains) { + num_thistime = MIN(num_domains, max_num_domains); + + r_u->status = STATUS_MORE_ENTRIES; + + if (q_u->enum_context + num_thistime > num_domains) { + num_thistime = num_domains - q_u->enum_context; + r_u->status = NT_STATUS_OK; + } + + next_idx = q_u->enum_context + num_thistime; + } else { + num_thistime = 0; + next_idx = 0xffffffff; + r_u->status = NT_STATUS_NO_MORE_ENTRIES; + } + /* set up the lsa_enum_trust_dom response */ - init_r_enum_trust_dom(p->mem_ctx, r_u, enum_context, max_num_domains, num_domains, trust_doms); + init_r_enum_trust_dom(p->mem_ctx, r_u, next_idx, + num_thistime, domains+q_u->enum_context); return r_u->status; } @@ -650,24 +586,29 @@ NTSTATUS _lsa_query_info(pipes_struct *p, LSA_Q_QUERY_INFO *q_u, LSA_R_QUERY_INF _lsa_lookup_sids ***************************************************************************/ -NTSTATUS _lsa_lookup_sids(pipes_struct *p, LSA_Q_LOOKUP_SIDS *q_u, LSA_R_LOOKUP_SIDS *r_u) +NTSTATUS _lsa_lookup_sids(pipes_struct *p, + LSA_Q_LOOKUP_SIDS *q_u, + LSA_R_LOOKUP_SIDS *r_u) { struct lsa_info *handle; - DOM_SID2 *sid = q_u->sids.sid; - int num_entries = q_u->sids.num_entries; - DOM_R_REF *ref = NULL; - LSA_TRANS_NAME_ENUM *names = NULL; + + int i, num_sids; + const DOM_SID **sids; uint32 mapped_count = 0; - if (num_entries > MAX_LOOKUP_SIDS) { - num_entries = 0; - DEBUG(5,("_lsa_lookup_sids: limit of %d exceeded, truncating SID lookup list to %d\n", MAX_LOOKUP_SIDS, num_entries)); - r_u->status = NT_STATUS_NONE_MAPPED; - } + struct lsa_dom_info *dom_infos; + struct lsa_name_info *name_infos; + + DOM_R_REF *ref = NULL; + LSA_TRANS_NAME_ENUM *names = NULL; - ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); names = TALLOC_ZERO_P(p->mem_ctx, LSA_TRANS_NAME_ENUM); + if ((q_u->level < 1) || (q_u->level > 6)) { + r_u->status = NT_STATUS_INVALID_PARAMETER; + goto done; + } + if (!find_policy_by_hnd(p, &q_u->pol, (void **)(void *)&handle)) { r_u->status = NT_STATUS_INVALID_HANDLE; goto done; @@ -678,19 +619,91 @@ NTSTATUS _lsa_lookup_sids(pipes_struct *p, LSA_Q_LOOKUP_SIDS *q_u, LSA_R_LOOKUP_ r_u->status = NT_STATUS_ACCESS_DENIED; goto done; } - if (!ref || !names) - return NT_STATUS_NO_MEMORY; -done: + num_sids = q_u->sids.num_entries; + if (num_sids > MAX_LOOKUP_SIDS) { + DEBUG(5,("_lsa_lookup_sids: limit of %d exceeded, truncating " + "SID lookup list to %d\n", + MAX_LOOKUP_SIDS, num_sids)); + r_u->status = NT_STATUS_NONE_MAPPED; + goto done; + } - /* set up the LSA Lookup SIDs response */ - init_lsa_trans_names(p->mem_ctx, ref, names, num_entries, sid, &mapped_count); - if (NT_STATUS_IS_OK(r_u->status)) { - if (mapped_count == 0) - r_u->status = NT_STATUS_NONE_MAPPED; - else if (mapped_count != num_entries) - r_u->status = STATUS_SOME_UNMAPPED; + ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); + + sids = TALLOC_ARRAY(p->mem_ctx, const DOM_SID *, num_sids); + if ((ref == NULL) || (names == NULL) || (sids == NULL)) { + r_u->status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i=0; isids.sid[i].sid; + } + + r_u->status = lookup_sids(p->mem_ctx, num_sids, sids, q_u->level, + &dom_infos, &name_infos); + + if (!NT_STATUS_IS_OK(r_u->status)) { + goto done; + } + + if (num_sids > 0) { + names->name = TALLOC_ARRAY(names, LSA_TRANS_NAME, num_sids); + names->uni_name = TALLOC_ARRAY(names, UNISTR2, num_sids); + if ((names->name == NULL) || (names->uni_name == NULL)) { + r_u->status = NT_STATUS_NO_MEMORY; + goto done; + } } + + for (i=0; istatus = NT_STATUS_INTERNAL_ERROR; + goto done; + } + } + + for (i=0; itype == SID_NAME_UNKNOWN) { + name->dom_idx = -1; + name->name = talloc_asprintf(p->mem_ctx, "%8.8x", + name->rid); + if (name->name == NULL) { + r_u->status = NT_STATUS_NO_MEMORY; + goto done; + } + } else { + mapped_count += 1; + } + init_lsa_trans_name(&names->name[i], &names->uni_name[i], + name->type, name->name, name->dom_idx); + } + + names->num_entries = num_sids; + names->ptr_trans_names = 1; + names->num_entries2 = num_sids; + + r_u->status = NT_STATUS_NONE_MAPPED; + if (mapped_count > 0) { + r_u->status = (mapped_count < num_sids) ? + STATUS_SOME_UNMAPPED : NT_STATUS_OK; + } + + DEBUG(10, ("num_sids %d, mapped_count %d, status %s\n", + num_sids, mapped_count, nt_errstr(r_u->status))); + + done: init_reply_lookup_sids(r_u, ref, names, mapped_count); return r_u->status; @@ -1173,10 +1186,7 @@ NTSTATUS _lsa_setsystemaccount(pipes_struct *p, LSA_Q_SETSYSTEMACCOUNT *q_u, LSA if (!pdb_getgrsid(&map, info->sid)) return NT_STATUS_NO_SUCH_GROUP; - if(!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_NO_SUCH_GROUP; - - return r_u->status; + return pdb_update_group_mapping_entry(&map); } /*************************************************************************** diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c index 643921f5963..fd78f954cc4 100644 --- a/source/rpc_server/srv_netlog_nt.c +++ b/source/rpc_server/srv_netlog_nt.c @@ -542,12 +542,9 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET * } become_root(); - ret = pdb_update_sam_account (sampass); + r_u->status = pdb_update_sam_account (sampass); unbecome_root(); } - if (ret) { - status = NT_STATUS_OK; - } /* set up the LSA Server Password Set response */ init_net_r_srv_pwset(r_u, &cred_out, status); @@ -587,29 +584,29 @@ NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOF /******************************************************************* gets a domain user's groups from their already-calculated NT_USER_TOKEN ********************************************************************/ -static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, - const NT_USER_TOKEN *nt_token, +static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + size_t num_sids, + const DOM_SID *sids, int *numgroups, DOM_GID **pgids) { - DOM_GID *gids; int i; - gids = TALLOC_ARRAY(mem_ctx, DOM_GID, nt_token->num_sids); - - if (!gids) { - return NT_STATUS_NO_MEMORY; - } - *numgroups=0; + *pgids = NULL; - for (i=PRIMARY_GROUP_SID_INDEX; i < nt_token->num_sids; i++) { - if (sid_compare_domain(domain_sid, &nt_token->user_sids[i])==0) { - sid_peek_rid(&nt_token->user_sids[i], &(gids[*numgroups].g_rid)); - gids[*numgroups].attr= (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_ENABLED); - (*numgroups)++; + for (i=0; idc->remote_machine )); return NT_STATUS_ACCESS_DENIED; } @@ -734,10 +731,10 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * break; } case INTERACTIVE_LOGON_TYPE: - /* 'Interactive' autheticaion, supplies the password in its - MD4 form, encrypted with the session key. We will - convert this to chellange/responce for the auth - subsystem to chew on */ + /* 'Interactive' authentication, supplies the password in its + MD4 form, encrypted with the session key. We will convert + this to challenge/response for the auth subsystem to chew + on */ { const uint8 *chal; @@ -787,14 +784,15 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * && !is_trusted_domain(nt_domain) ) r_u->auth_resp = 0; /* We are not authoritative */ - free_server_info(&server_info); + talloc_free(server_info); return status; } if (server_info->guest) { /* We don't like guest domain logons... */ - DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n")); - free_server_info(&server_info); + DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST " + "denied.\n")); + talloc_free(server_info); return NT_STATUS_LOGON_FAILURE; } @@ -819,7 +817,8 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * sampw = server_info->sam_account; - /* set up pointer indicating user/password failed to be found */ + /* set up pointer indicating user/password failed to be + * found */ usr_info->ptr_user_info = 0; user_sid = pdb_get_user_sid(sampw); @@ -829,8 +828,12 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * sid_split_rid(&domain_sid, &user_rid); if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { - DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", - pdb_get_domain(sampw), pdb_get_username(sampw), + DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid " + "%s\n but group sid %s.\n" + "The conflicting domain portions are not " + "supported for NETLOGON calls\n", + pdb_get_domain(sampw), + pdb_get_username(sampw), sid_to_string(user_sid_string, user_sid), sid_to_string(group_sid_string, group_sid))); return NT_STATUS_UNSUCCESSFUL; @@ -842,26 +845,30 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * } else { pstrcpy(my_name, global_myname()); } - - if (!NT_STATUS_IS_OK(status - = nt_token_to_group_list(p->mem_ctx, - &domain_sid, - server_info->ptok, - &num_gids, - &gids))) { + + status = nt_token_to_group_list(p->mem_ctx, &domain_sid, + server_info->num_sids, + server_info->sids, + &num_gids, &gids); + + if (!NT_STATUS_IS_OK(status)) { return status; } ZERO_STRUCT(netlogon_sess_key); memcpy(netlogon_sess_key, p->dc->sess_key, 8); if (server_info->user_session_key.length) { - memcpy(user_session_key, server_info->user_session_key.data, - MIN(sizeof(user_session_key), server_info->user_session_key.length)); + memcpy(user_session_key, + server_info->user_session_key.data, + MIN(sizeof(user_session_key), + server_info->user_session_key.length)); SamOEMhash(user_session_key, netlogon_sess_key, 16); } if (server_info->lm_session_key.length) { - memcpy(lm_session_key, server_info->lm_session_key.data, - MIN(sizeof(lm_session_key), server_info->lm_session_key.length)); + memcpy(lm_session_key, + server_info->lm_session_key.data, + MIN(sizeof(lm_session_key), + server_info->lm_session_key.length)); SamOEMhash(lm_session_key, netlogon_sess_key, 16); } ZERO_STRUCT(netlogon_sess_key); @@ -891,14 +898,11 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * server_info->lm_session_key.length ? lm_session_key : NULL, my_name , /* char *logon_srv */ pdb_get_domain(sampw), - &domain_sid, /* DOM_SID *dom_sid */ - /* Should be users domain sid, not servers - for trusted domains */ - - NULL); /* char *other_sids */ + &domain_sid); /* DOM_SID *dom_sid */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); } - free_server_info(&server_info); + talloc_free(server_info); return status; } diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c index 381adbe6358..68b3a2d434c 100644 --- a/source/rpc_server/srv_pipe.c +++ b/source/rpc_server/srv_pipe.c @@ -616,7 +616,7 @@ static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) memset(p->wks, '\0', sizeof(p->wks)); /* Set up for non-authenticated user. */ - delete_nt_token(&p->pipe_user.nt_user_token); + talloc_free(p->pipe_user.nt_user_token); p->pipe_user.ut.ngroups = 0; SAFE_FREE( p->pipe_user.ut.groups); @@ -664,7 +664,8 @@ static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) } if (a->server_info->ptok) { - p->pipe_user.nt_user_token = dup_nt_token(a->server_info->ptok); + p->pipe_user.nt_user_token = + dup_nt_token(NULL, a->server_info->ptok); } else { DEBUG(1,("Error: Authmodule failed to provide nt_user_token\n")); p->pipe_user.nt_user_token = NULL; diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c index 37d3ef64c0b..86a04e7ccbe 100644 --- a/source/rpc_server/srv_pipe_hnd.c +++ b/source/rpc_server/srv_pipe_hnd.c @@ -349,7 +349,8 @@ static void *make_internal_rpc_pipe_p(char *pipe_name, /* Store the session key and NT_TOKEN */ if (vuser) { p->session_key = data_blob(vuser->session_key.data, vuser->session_key.length); - p->pipe_user.nt_user_token = dup_nt_token(vuser->nt_user_token); + p->pipe_user.nt_user_token = dup_nt_token( + NULL, vuser->nt_user_token); } /* @@ -1222,7 +1223,7 @@ static BOOL close_internal_rpc_pipe_hnd(void *np_conn) /* Free the handles database. */ close_policy_by_pipe(p); - delete_nt_token(&p->pipe_user.nt_user_token); + talloc_free(p->pipe_user.nt_user_token); data_blob_free(&p->session_key); SAFE_FREE(p->pipe_user.ut.groups); diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index 2f9d494a26f..81344cdc1ec 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -140,7 +140,7 @@ static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd if ( sid ) { init_sec_access( &mask, sid_access ); init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); -} + } /* create the security descriptor */ @@ -1416,7 +1416,7 @@ NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LO type[i] = SID_NAME_ALIAS; } } else { - lookup_global_sam_name(name, &rid[i], &type[i]); + lookup_global_sam_name(name, 0, &rid[i], &type[i]); } if (type[i] != SID_NAME_UNKNOWN) { @@ -1927,28 +1927,6 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ return r_u->status; break; -#if 0 -/* whoops - got this wrong. i think. or don't understand what's happening. */ - case 17: - { - NTTIME expire; - info = (void *)&id11; - - expire.low = 0xffffffff; - expire.high = 0x7fffffff; - - ctr->info.id = TALLOC_ZERO_P(p->mem_ctx, SAM_USER_INFO_17)); - ZERO_STRUCTP(ctr->info.id17); - init_sam_user_info17(ctr->info.id17, &expire, - "BROOKFIELDS$", /* name */ - 0x03ef, /* user rid */ - 0x201, /* group rid */ - 0x0080); /* acb info */ - - break; - } -#endif - case 18: ctr->info.id18 = TALLOC_ZERO_P(p->mem_ctx, SAM_USER_INFO_18); if (ctr->info.id18 == NULL) @@ -1993,10 +1971,11 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ NTSTATUS _samr_query_usergroups(pipes_struct *p, SAMR_Q_QUERY_USERGROUPS *q_u, SAMR_R_QUERY_USERGROUPS *r_u) { SAM_ACCOUNT *sam_pass=NULL; - struct passwd *passwd; DOM_SID sid; DOM_SID *sids; + DOM_GID dom_gid; DOM_GID *gids = NULL; + uint32 primary_group_rid; size_t num_groups = 0; gid_t *unix_gids; size_t i, num_gids; @@ -2031,58 +2010,72 @@ NTSTATUS _samr_query_usergroups(pipes_struct *p, SAMR_Q_QUERY_USERGROUPS *q_u, S if (!sid_check_is_in_our_domain(&sid)) return NT_STATUS_OBJECT_TYPE_MISMATCH; - pdb_init_sam(&sam_pass); + pdb_init_sam_talloc(p->mem_ctx, &sam_pass); become_root(); ret = pdb_getsampwsid(sam_pass, &sid); unbecome_root(); - if (ret == False) { - pdb_free_sam(&sam_pass); - return NT_STATUS_NO_SUCH_USER; - } - - passwd = getpwnam_alloc(pdb_get_username(sam_pass)); - if (passwd == NULL) { - pdb_free_sam(&sam_pass); + if (!ret) { + DEBUG(10, ("pdb_getsampwsid failed for %s\n", + sid_string_static(&sid))); return NT_STATUS_NO_SUCH_USER; } sids = NULL; become_root(); - result = pdb_enum_group_memberships(pdb_get_username(sam_pass), - passwd->pw_gid, + result = pdb_enum_group_memberships(p->mem_ctx, sam_pass, &sids, &unix_gids, &num_groups); unbecome_root(); - pdb_free_sam(&sam_pass); - passwd_free(&passwd); - - if (!NT_STATUS_IS_OK(result)) + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_enum_group_memberships failed for %s\n", + sid_string_static(&sid))); return result; - - SAFE_FREE(unix_gids); + } gids = NULL; num_gids = 0; + dom_gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT| + SE_GROUP_ENABLED); + + if (!sid_peek_check_rid(get_global_sam_sid(), + pdb_get_group_sid(sam_pass), + &primary_group_rid)) { + DEBUG(5, ("Group sid %s for user %s not in our domain\n", + sid_string_static(pdb_get_group_sid(sam_pass)), + pdb_get_username(sam_pass))); + pdb_free_sam(&sam_pass); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + dom_gid.g_rid = primary_group_rid; + + ADD_TO_ARRAY(p->mem_ctx, DOM_GID, dom_gid, &gids, &num_gids); + for (i=0; imem_ctx, gids, DOM_GID, num_gids+1); - gids[num_gids].attr= (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_ENABLED); - gids[num_gids].g_rid = rid; - num_gids += 1; + if (dom_gid.g_rid == primary_group_rid) { + /* We added the primary group directly from the + * sam_account. The other SIDs are unique from + * enum_group_memberships */ + continue; + } + + ADD_TO_ARRAY(p->mem_ctx, DOM_GID, dom_gid, &gids, &num_gids); } - SAFE_FREE(sids); /* construct the response. lkclXXXX: gids are not copied! */ - init_samr_r_query_usergroups(r_u, num_groups, gids, r_u->status); + init_samr_r_query_usergroups(r_u, num_gids, gids, r_u->status); DEBUG(5,("_samr_query_usergroups: %d\n", __LINE__)); @@ -2322,7 +2315,8 @@ static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name) This funcion will need to be updated for bdc/domain trusts. ********************************************************************/ -NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREATE_USER *r_u) +NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, + SAMR_R_CREATE_USER *r_u) { SAM_ACCOUNT *sam_pass=NULL; fstring account; @@ -2339,7 +2333,6 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA uint32 acc_granted; SEC_DESC *psd; size_t sd_size; - uint32 new_rid = 0; /* check this, when giving away 'add computer to domain' privs */ uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; BOOL can_add_account = False; @@ -2347,20 +2340,26 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA DISP_INFO *disp_info = NULL; /* Get the domain SID stored in the domain policy */ - if (!get_lsa_policy_samr_sid(p, &dom_pol, &sid, &acc_granted, &disp_info)) + if (!get_lsa_policy_samr_sid(p, &dom_pol, &sid, &acc_granted, + &disp_info)) return NT_STATUS_INVALID_HANDLE; - if (!NT_STATUS_IS_OK(nt_status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_CREATE_USER, "_samr_create_user"))) { + nt_status = access_check_samr_function(acc_granted, + SA_RIGHT_DOMAIN_CREATE_USER, + "_samr_create_user"); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } - if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST || acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) { + if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST || + acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) { /* Match Win2k, and return NT_STATUS_INVALID_PARAMETER if this parameter is not an account type */ return NT_STATUS_INVALID_PARAMETER; } - rpcstr_pull(account, user_account.buffer, sizeof(account), user_account.uni_str_len*2, 0); + rpcstr_pull(account, user_account.buffer, sizeof(account), + user_account.uni_str_len*2, 0); strlower_m(account); nt_status = can_create(p->mem_ctx, account); @@ -2369,14 +2368,14 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA } /********************************************************************* - * HEADS UP! If we have to create a new user account, we have to get - * a new RID from somewhere. This used to be done by the passdb - * backend. It has been moved into idmap now. Since idmap is now - * wrapped up behind winbind, this means you have to run winbindd if you - * want new accounts to get a new RID when "enable rid algorithm = no". - * Tough. We now have a uniform way of allocating RIDs regardless - * of what ever passdb backend people may use. - * --jerry (2003-07-10) + * HEADS UP! If we have to create a new user account, we have to get + * a new RID from somewhere. This used to be done by the passdb + * backend. It has been moved into idmap now. Since idmap is now + * wrapped up behind winbind, this means you have to run winbindd if + * you want new accounts to get a new RID when "enable rid algorithm = + * no". Tough. We now have a uniform way of allocating RIDs + * regardless of what ever passdb backend people may use. --jerry + * (2003-07-10) *********************************************************************/ pw = Get_Pwnam(account); @@ -2387,24 +2386,30 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA { pstrcpy(add_script, lp_addmachine_script()); se_priv_copy( &se_rights, &se_machine_account ); - can_add_account = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_account = user_has_privileges( + p->pipe_user.nt_user_token, &se_rights ); } /* usrmgr.exe (and net rpc trustdom grant) creates a normal user account for domain trusts and changes the ACB flags later */ - else if ( acb_info & ACB_NORMAL && (account[strlen(account)-1] != '$') ) + else if ( acb_info & ACB_NORMAL && + (account[strlen(account)-1] != '$') ) { pstrcpy(add_script, lp_adduser_script()); se_priv_copy( &se_rights, &se_add_users ); - can_add_account = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_account = user_has_privileges( + p->pipe_user.nt_user_token, &se_rights ); } - else /* implicit assumption of a BDC or domain trust account here (we already check the flags earlier) */ + else /* implicit assumption of a BDC or domain trust account here + * (we already check the flags earlier) */ { pstrcpy(add_script, lp_addmachine_script()); if ( lp_enable_privileges() ) { /* only Domain Admins can add a BDC or domain trust */ se_priv_copy( &se_rights, &se_priv_none ); - can_add_account = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ); - } + can_add_account = nt_token_check_domain_rid( + p->pipe_user.nt_user_token, + DOMAIN_GROUP_RID_ADMINS ); + } } DEBUG(5, ("_samr_create_user: %s can add this account : %s\n", @@ -2419,16 +2424,20 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA if (*add_script) { int add_ret; - all_string_sub(add_script, "%u", account, sizeof(add_script)); + all_string_sub(add_script, "%u", account, + 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)); + DEBUG(add_ret ? 0 : 3,("_samr_create_user: Running " + "the command `%s' gave %d\n", + add_script, add_ret)); } } - /* implicit call to getpwnam() next. we have a valid SID coming out of this call */ + /* implicit call to getpwnam() next. we have a valid SID coming out + * of this call */ flush_pwnam_cache(); - nt_status = pdb_init_sam_new(&sam_pass, account, new_rid); + nt_status = pdb_init_sam_new(&sam_pass, account); /* this code is order such that we have no unnecessary retuns out of the admin block of code */ @@ -2438,7 +2447,8 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA if ( !(ret = pdb_add_sam_account(sam_pass)) ) { pdb_free_sam(&sam_pass); - DEBUG(0, ("could not add user/computer %s to passdb. Check permissions?\n", + DEBUG(0, ("could not add user/computer %s to passdb. " + "Check permissions?\n", account)); nt_status = NT_STATUS_ACCESS_DENIED; } @@ -2458,7 +2468,8 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA sid_copy(&sid, pdb_get_user_sid(sam_pass)); - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, + &sid, SAMR_USR_RIGHTS_WRITE_PW); se_map_generic(&des_access, &usr_generic_mapping); nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, @@ -2944,7 +2955,7 @@ static BOOL set_user_info_16(const SAM_USER_INFO_16 *id16, SAM_ACCOUNT *pwd) return False; } - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -2980,7 +2991,7 @@ static BOOL set_user_info_18(SAM_USER_INFO_18 *id18, SAM_ACCOUNT *pwd) return False; } - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -2997,8 +3008,7 @@ static BOOL set_unix_primary_group(SAM_ACCOUNT *sampass) struct group *grp; gid_t gid; - if (!NT_STATUS_IS_OK(sid_to_gid(pdb_get_group_sid(sampass), - &gid))) { + if (!sid_to_gid(pdb_get_group_sid(sampass), &gid)) { DEBUG(2,("Could not get gid for primary group of " "user %s\n", pdb_get_username(sampass))); return False; @@ -3039,7 +3049,7 @@ static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, SAM_ACCOUNT *pwd) copy_id20_to_sam_passwd(pwd, id20); /* write the change out */ - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -3073,7 +3083,7 @@ static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd) set_unix_primary_group(pwd); /* write the change out */ - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -3140,7 +3150,7 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, SAM_ACCOUNT *pwd) if (IS_SAM_CHANGED(pwd, PDB_GROUPSID)) set_unix_primary_group(pwd); - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -3202,7 +3212,7 @@ static BOOL set_user_info_pw(uint8 *pass, SAM_ACCOUNT *pwd) DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n")); /* update the SAMBA password */ - if(!pdb_update_sam_account(pwd)) { + if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); return False; } @@ -3485,7 +3495,6 @@ NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, NTSTATUS ntstatus2; DOM_SID *members; - BOOL res; r_u->status = NT_STATUS_OK; @@ -3521,13 +3530,14 @@ NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, num_alias_rids = 0; become_root(); - res = pdb_enum_alias_memberships(p->mem_ctx, &info->sid, members, - q_u->num_sids1, - &alias_rids, &num_alias_rids); + ntstatus1 = pdb_enum_alias_memberships(p->mem_ctx, &info->sid, members, + q_u->num_sids1, + &alias_rids, &num_alias_rids); unbecome_root(); - if (!res) - return NT_STATUS_UNSUCCESSFUL; + if (!NT_STATUS_IS_OK(ntstatus1)) { + return ntstatus1; + } init_samr_r_query_useraliases(r_u, num_alias_rids, alias_rids, NT_STATUS_OK); @@ -3540,6 +3550,7 @@ NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_R_QUERY_ALIASMEM *r_u) { + NTSTATUS status; size_t i; size_t num_sids = 0; DOM_SID2 *sid; @@ -3560,8 +3571,11 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_ DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid))); - if (!pdb_enum_aliasmem(&alias_sid, &sids, &num_sids)) - return NT_STATUS_NO_SUCH_ALIAS; + status = pdb_enum_aliasmem(&alias_sid, &sids, &num_sids); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } sid = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_SID2, num_sids); if (num_sids!=0 && sid == NULL) { @@ -3710,7 +3724,7 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD uint32 acc_granted; SE_PRIV se_rights; BOOL can_add_accounts; - BOOL ret; + NTSTATUS ret; DISP_INFO *disp_info = NULL; /* Find the policy handle. Open a policy on it. */ @@ -3738,11 +3752,11 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD /******** END SeAddUsers BLOCK *********/ - if (ret) { + if (NT_STATUS_IS_OK(ret)) { force_flush_samr_cache(disp_info); } - return ret ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + return ret; } /********************************************************************* @@ -3755,7 +3769,7 @@ NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DE uint32 acc_granted; SE_PRIV se_rights; BOOL can_add_accounts; - BOOL ret; + NTSTATUS ret; DISP_INFO *disp_info = NULL; /* Find the policy handle. Open a policy on it. */ @@ -3784,11 +3798,11 @@ NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DE /******** END SeAddUsers BLOCK *********/ - if (ret) { + if (NT_STATUS_IS_OK(ret)) { force_flush_samr_cache(disp_info); } - return ret ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + return ret; } /********************************************************************* @@ -3847,19 +3861,18 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD } /* check a real user exist before we run the script to add a user to a group */ - if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sam_user), &uid))) { + if (!sid_to_uid(pdb_get_user_sid(sam_user), &uid)) { pdb_free_sam(&sam_user); return NT_STATUS_NO_SUCH_USER; } pdb_free_sam(&sam_user); - if ((pwd=getpwuid_alloc(uid)) == NULL) { + if ((pwd=getpwuid_alloc(p->mem_ctx, uid)) == NULL) { return NT_STATUS_NO_SUCH_USER; } if ((grp=getgrgid(map.gid)) == NULL) { - passwd_free(&pwd); return NT_STATUS_NO_SUCH_GROUP; } @@ -3867,8 +3880,7 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD fstrcpy(grp_name, grp->gr_name); /* if the user is already in the group */ - if(user_in_unix_group_list(pwd->pw_name, grp_name)) { - passwd_free(&pwd); + if(user_in_unix_group(pwd->pw_name, grp_name)) { return NT_STATUS_MEMBER_IN_GROUP; } @@ -3894,13 +3906,10 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD /******** END SeAddUsers BLOCK *********/ /* check if the user has been added then ... */ - if(!user_in_unix_group_list(pwd->pw_name, grp_name)) { - passwd_free(&pwd); + if(!user_in_unix_group(pwd->pw_name, grp_name)) { return NT_STATUS_MEMBER_NOT_IN_GROUP; /* don't know what to reply else */ } - passwd_free(&pwd); - force_flush_samr_cache(disp_info); return NT_STATUS_OK; @@ -3961,7 +3970,7 @@ NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DE } /* if the user is not in the group */ - if (!user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) { + if (!user_in_unix_group(pdb_get_username(sam_pass), grp_name)) { pdb_free_sam(&sam_pass); return NT_STATUS_MEMBER_NOT_IN_GROUP; } @@ -3983,7 +3992,7 @@ NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DE /******** END SeAddUsers BLOCK *********/ /* check if the user has been removed then ... */ - if (user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) { + if (user_in_unix_group(pdb_get_username(sam_pass), grp_name)) { pdb_free_sam(&sam_pass); return NT_STATUS_ACCESS_DENIED; /* don't know what to reply else */ } @@ -4290,19 +4299,28 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S /* so far, so good */ result = NT_STATUS_OK; - - r_u->rid = pdb_gid_to_group_rid( grp->gr_gid ); - /* add the group to the mapping table */ + if (pdb_rid_algorithm()) { + r_u->rid = pdb_gid_to_group_rid( grp->gr_gid ); + } else { + if (!pdb_new_rid(&r_u->rid)) { + result = NT_STATUS_ACCESS_DENIED; + } + } + + if (NT_STATUS_IS_OK(result)) { + + /* add the group to the mapping table */ - sid_copy( &info_sid, get_global_sam_sid() ); - sid_append_rid( &info_sid, r_u->rid ); - sid_to_string( sid_string, &info_sid ); + sid_copy( &info_sid, get_global_sam_sid() ); + sid_append_rid( &info_sid, r_u->rid ); + sid_to_string( sid_string, &info_sid ); - /* reset the error code if we fail to add the mapping entry */ + /* reset the error code if we fail to add the mapping entry */ - if ( !add_initial_entry(grp->gr_gid, sid_string, SID_NAME_DOM_GRP, name, NULL) ) - result = NT_STATUS_ACCESS_DENIED; + if ( !add_initial_entry(grp->gr_gid, sid_string, SID_NAME_DOM_GRP, name, NULL) ) + result = NT_STATUS_ACCESS_DENIED; + } } if ( can_add_accounts ) @@ -4383,18 +4401,26 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S /******** END SeAddUsers BLOCK *********/ - if (!NT_STATUS_IS_OK(result)) + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_create_alias failed: %s\n", + nt_errstr(result))); return result; + } sid_copy(&info_sid, get_global_sam_sid()); sid_append_rid(&info_sid, r_u->rid); - if (!NT_STATUS_IS_OK(sid_to_gid(&info_sid, &gid))) + if (!sid_to_gid(&info_sid, &gid)) { + DEBUG(10, ("Could not find alias just created\n")); return NT_STATUS_ACCESS_DENIED; + } /* check if the group has been successfully created */ - if ( getgrgid(gid) == NULL ) + if ( getgrgid(gid) == NULL ) { + DEBUG(10, ("getgrgid(%d) of just created alias failed\n", + gid)); return NT_STATUS_ACCESS_DENIED; + } if ((info = get_samr_info_by_sid(&info_sid)) == NULL) return NT_STATUS_NO_MEMORY; @@ -4485,7 +4511,8 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_ GROUP_MAP map; GROUP_INFO_CTR *ctr; uint32 acc_granted; - BOOL ret; + NTSTATUS ret; + BOOL result; BOOL can_mod_accounts; DISP_INFO *disp_info = NULL; @@ -4497,9 +4524,9 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_ } become_root(); - ret = get_domain_group_from_sid(group_sid, &map); + result = get_domain_group_from_sid(group_sid, &map); unbecome_root(); - if (!ret) + if (!result) return NT_STATUS_NO_SUCH_GROUP; ctr=q_u->ctr; @@ -4529,11 +4556,11 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_ /******** End SeAddUsers BLOCK *********/ - if (ret) { + if (NT_STATUS_IS_OK(ret)) { force_flush_samr_cache(disp_info); } - return ret ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + return ret; } /********************************************************************* diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index a22d6db266c..e6d45f76ec0 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -1620,10 +1620,13 @@ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, and not a printer admin, then fail */ - if ( user.ut.uid != 0 - && !user_has_privileges( user.nt_user_token, &se_printop ) - && !user_in_list(uidtoname(user.ut.uid), lp_printer_admin(snum), user.ut.groups, user.ut.ngroups) ) - { + if ((user.ut.uid != 0) && + !user_has_privileges(user.nt_user_token, + &se_printop ) && + !token_contains_name_in_list( + uidtoname(user.ut.uid), NULL, + user.nt_user_token, + lp_printer_admin(snum))) { close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } @@ -1676,7 +1679,10 @@ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, return WERR_ACCESS_DENIED; } - if (!user_ok(uidtoname(user.ut.uid), snum, user.ut.groups, user.ut.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) { + if (!user_ok_token(uidtoname(user.ut.uid), user.nt_user_token, + snum) || + !print_access_check(&user, snum, + printer_default->access_required)) { DEBUG(3, ("access DENIED for printer open\n")); close_printer_handle(p, handle); return WERR_ACCESS_DENIED; @@ -5997,7 +6003,7 @@ BOOL add_printer_hook(NT_USER_TOKEN *token, NT_PRINTER_INFO_LEVEL *printer) numlines = 0; /* Get lines and convert them back to dos-codepage */ - qlines = fd_lines_load(fd, &numlines); + qlines = fd_lines_load(fd, &numlines, 0); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); close(fd); @@ -7195,7 +7201,7 @@ WERROR enumports_hook( int *count, char ***lines ) } numlines = 0; - qlines = fd_lines_load(fd, &numlines); + qlines = fd_lines_load(fd, &numlines, 0); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); close(fd); } diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index 8150a8bf698..f279c98c312 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -29,26 +29,6 @@ extern struct generic_mapping file_generic_mapping; #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV -#define INVALID_SHARENAME_CHARS "<>*?|/\\+=;:\"," - -/******************************************************************** - Check a string for any occurrences of a specified list of invalid - characters. -********************************************************************/ - -static BOOL validate_net_name( const char *name, const char *invalid_chars, int max_len ) -{ - int i; - - for ( i=0; iinfo_2_str, net_name, remark, path, passwd); } -/******************************************************************* - What to do when smb.conf is updated. - ********************************************************************/ - -static void smb_conf_updated(int msg_type, struct process_id src, - void *buf, size_t len) -{ - DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n")); - reload_services(False); -} - -/******************************************************************* - Create the share security tdb. - ********************************************************************/ - -static TDB_CONTEXT *share_tdb; /* used for share security descriptors */ -#define SHARE_DATABASE_VERSION_V1 1 -#define SHARE_DATABASE_VERSION_V2 2 /* version id in little endian. */ - -BOOL share_info_db_init(void) -{ - static pid_t local_pid; - const char *vstring = "INFO/version"; - int32 vers_id; - - if (share_tdb && local_pid == sys_getpid()) - return True; - share_tdb = tdb_open_log(lock_path("share_info.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); - if (!share_tdb) { - DEBUG(0,("Failed to open share info database %s (%s)\n", - lock_path("share_info.tdb"), strerror(errno) )); - return False; - } - - local_pid = sys_getpid(); - - /* handle a Samba upgrade */ - tdb_lock_bystring(share_tdb, vstring, 0); - - /* Cope with byte-reversed older versions of the db. */ - vers_id = tdb_fetch_int32(share_tdb, vstring); - if ((vers_id == SHARE_DATABASE_VERSION_V1) || (IREV(vers_id) == SHARE_DATABASE_VERSION_V1)) { - /* Written on a bigendian machine with old fetch_int code. Save as le. */ - tdb_store_int32(share_tdb, vstring, SHARE_DATABASE_VERSION_V2); - vers_id = SHARE_DATABASE_VERSION_V2; - } - - if (vers_id != SHARE_DATABASE_VERSION_V2) { - tdb_traverse(share_tdb, tdb_traverse_delete_fn, NULL); - tdb_store_int32(share_tdb, vstring, SHARE_DATABASE_VERSION_V2); - } - tdb_unlock_bystring(share_tdb, vstring); - - message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); - - return True; -} - -/******************************************************************* - Fake up a Everyone, full access as a default. - ********************************************************************/ - -static SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, int snum, size_t *psize) -{ - SEC_ACCESS sa; - SEC_ACE ace; - SEC_ACL *psa = NULL; - SEC_DESC *psd = NULL; - uint32 def_access = GENERIC_ALL_ACCESS; - - se_map_generic(&def_access, &file_generic_mapping); - - init_sec_access(&sa, GENERIC_ALL_ACCESS | def_access ); - init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0); - - if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &ace)) != NULL) { - psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, psize); - } - - if (!psd) { - DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n")); - return NULL; - } - - return psd; -} - -/******************************************************************* - Pull a security descriptor from the share tdb. - ********************************************************************/ - -static SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize) -{ - prs_struct ps; - fstring key; - SEC_DESC *psd = NULL; - - *psize = 0; - - /* Fetch security descriptor from tdb */ - - slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum)); - - if (tdb_prs_fetch(share_tdb, key, &ps, ctx)!=0 || - !sec_io_desc("get_share_security", &psd, &ps, 1)) { - - DEBUG(4,("get_share_security: using default secdesc for %s\n", lp_servicename(snum) )); - - return get_share_security_default(ctx, snum, psize); - } - - if (psd) - *psize = sec_desc_size(psd); - - prs_mem_free(&ps); - return psd; -} - -/******************************************************************* - Store a security descriptor in the share db. - ********************************************************************/ - -static BOOL set_share_security(TALLOC_CTX *ctx, const char *share_name, SEC_DESC *psd) -{ - prs_struct ps; - TALLOC_CTX *mem_ctx = NULL; - fstring key; - BOOL ret = False; - - mem_ctx = talloc_init("set_share_security"); - if (mem_ctx == NULL) - return False; - - prs_init(&ps, (uint32)sec_desc_size(psd), mem_ctx, MARSHALL); - - if (!sec_io_desc("share_security", &psd, &ps, 1)) - goto out; - - slprintf(key, sizeof(key)-1, "SECDESC/%s", share_name); - - if (tdb_prs_store(share_tdb, key, &ps)==0) { - ret = True; - DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name )); - } else { - DEBUG(1,("set_share_security: Failed to store secdesc for %s\n", share_name )); - } - - /* Free malloc'ed memory */ - -out: - - prs_mem_free(&ps); - if (mem_ctx) - talloc_destroy(mem_ctx); - return ret; -} - -/******************************************************************* - Delete a security descriptor. -********************************************************************/ - -static BOOL delete_share_security(int snum) -{ - TDB_DATA kbuf; - fstring key; - - slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum)); - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; - - if (tdb_delete(share_tdb, kbuf) != 0) { - DEBUG(0,("delete_share_security: Failed to delete entry for share %s\n", - lp_servicename(snum) )); - return False; - } - - return True; -} - /******************************************************************* Map any generic bits to file specific bits. ********************************************************************/ -void map_generic_share_sd_bits(SEC_DESC *psd) +static void map_generic_share_sd_bits(SEC_DESC *psd) { int i; SEC_ACL *ps_dacl = NULL; @@ -517,7 +318,7 @@ static BOOL init_srv_share_info_ctr(pipes_struct *p, SRV_SHARE_INFO_CTR *ctr, uint32 info_level, uint32 *resume_hnd, uint32 *total_entries, BOOL all_shares) { int num_entries = 0; - int num_services = lp_numservices(); + int num_services = 0; int snum; TALLOC_CTX *ctx = p->mem_ctx; @@ -528,6 +329,11 @@ static BOOL init_srv_share_info_ctr(pipes_struct *p, SRV_SHARE_INFO_CTR *ctr, ctr->info_level = ctr->switch_value = info_level; *resume_hnd = 0; + /* Ensure all the usershares are loaded. */ + become_root(); + num_services = load_usershare_shares(); + unbecome_root(); + /* Count the number of entries. */ for (snum = 0; snum < num_services; snum++) { if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_hidden_share(snum)) ) diff --git a/source/rpcclient/cmd_dfs.c b/source/rpcclient/cmd_dfs.c index 956dbfa4027..b4d43bda5ee 100644 --- a/source/rpcclient/cmd_dfs.c +++ b/source/rpcclient/cmd_dfs.c @@ -3,6 +3,7 @@ RPC pipe client Copyright (C) Tim Potter 2000 + Copyright (C) Jelmer Vernooij 2005. 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 @@ -27,7 +28,7 @@ static NTSTATUS cmd_dfs_exist(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { - BOOL dfs_exists; + uint32 dfs_exists; NTSTATUS result; if (argc != 1) { @@ -35,7 +36,7 @@ static NTSTATUS cmd_dfs_exist(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } - result = rpccli_dfs_exist(cli, mem_ctx, &dfs_exists); + result = rpccli_dfs_GetManagerVersion(cli, mem_ctx, &dfs_exists); if (NT_STATUS_IS_OK(result)) printf("dfs is %spresent\n", dfs_exists ? "" : "not "); @@ -47,21 +48,21 @@ static NTSTATUS cmd_dfs_add(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS result; - const char *entrypath, *servername, *sharename, *comment; + const char *path, *servername, *sharename, *comment; uint32 flags = 0; if (argc != 5) { - printf("Usage: %s entrypath servername sharename comment\n", + printf("Usage: %s path servername sharename comment\n", argv[0]); return NT_STATUS_OK; } - entrypath = argv[1]; + path = argv[1]; servername = argv[2]; sharename = argv[3]; comment = argv[4]; - result = rpccli_dfs_add(cli, mem_ctx, entrypath, servername, + result = rpccli_dfs_Add(cli, mem_ctx, path, servername, sharename, comment, flags); return result; @@ -71,18 +72,18 @@ static NTSTATUS cmd_dfs_remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS result; - const char *entrypath, *servername, *sharename; + const char *path, *servername, *sharename; if (argc != 4) { - printf("Usage: %s entrypath servername sharename\n", argv[0]); + printf("Usage: %s path servername sharename\n", argv[0]); return NT_STATUS_OK; } - entrypath = argv[1]; + path = argv[1]; servername = argv[2]; sharename = argv[3]; - result = rpccli_dfs_remove(cli, mem_ctx, entrypath, servername, + result = rpccli_dfs_Remove(cli, mem_ctx, path, servername, sharename); return result; @@ -90,78 +91,92 @@ static NTSTATUS cmd_dfs_remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, /* Display a DFS_INFO_1 structure */ -static void display_dfs_info_1(DFS_INFO_1 *info1) +static void display_dfs_info_1(NETDFS_DFS_INFO1 *info1) { fstring temp; - unistr2_to_ascii(temp, &info1->entrypath, sizeof(temp) - 1); - printf("entrypath: %s\n", temp); + unistr2_to_ascii(temp, &info1->path, sizeof(temp) - 1); + printf("path: %s\n", temp); } /* Display a DFS_INFO_2 structure */ -static void display_dfs_info_2(DFS_INFO_2 *info2) +static void display_dfs_info_2(NETDFS_DFS_INFO2 *info2) { fstring temp; - unistr2_to_ascii(temp, &info2->entrypath, sizeof(temp) - 1); - printf("entrypath: %s\n", temp); + unistr2_to_ascii(temp, &info2->path, sizeof(temp) - 1); + printf("path: %s\n", temp); unistr2_to_ascii(temp, &info2->comment, sizeof(temp) - 1); printf("\tcomment: %s\n", temp); printf("\tstate: %d\n", info2->state); - printf("\tnum_storages: %d\n", info2->num_storages); + printf("\tnum_stores: %d\n", info2->num_stores); } /* Display a DFS_INFO_3 structure */ -static void display_dfs_info_3(DFS_INFO_3 *info3) +static void display_dfs_info_3(NETDFS_DFS_INFO3 *info3) { fstring temp; int i; - unistr2_to_ascii(temp, &info3->entrypath, sizeof(temp) - 1); - printf("entrypath: %s\n", temp); + unistr2_to_ascii(temp, &info3->path, sizeof(temp) - 1); + printf("path: %s\n", temp); unistr2_to_ascii(temp, &info3->comment, sizeof(temp) - 1); printf("\tcomment: %s\n", temp); printf("\tstate: %d\n", info3->state); - printf("\tnum_storages: %d\n", info3->num_storages); + printf("\tnum_stores: %d\n", info3->num_stores); - for (i = 0; i < info3->num_storages; i++) { - DFS_STORAGE_INFO *dsi = &info3->storages[i]; + for (i = 0; i < info3->num_stores; i++) { + NETDFS_DFS_STORAGEINFO *dsi = &info3->stores[i]; - unistr2_to_ascii(temp, &dsi->servername, sizeof(temp) - 1); - printf("\t\tstorage[%d] servername: %s\n", i, temp); + unistr2_to_ascii(temp, &dsi->server, sizeof(temp) - 1); + printf("\t\tstorage[%d] server: %s\n", i, temp); - unistr2_to_ascii(temp, &dsi->sharename, sizeof(temp) - 1); - printf("\t\tstorage[%d] sharename: %s\n", i, temp); + unistr2_to_ascii(temp, &dsi->share, sizeof(temp) - 1); + printf("\t\tstorage[%d] share: %s\n", i, temp); } } -/* Display a DFS_INFO_CTR structure */ -static void display_dfs_info_ctr(DFS_INFO_CTR *ctr) +/* Display a DFS_INFO_CTR structure */ +static void display_dfs_info(NETDFS_DFS_INFO_CTR *ctr) { - int i; - - for (i = 0; i < ctr->num_entries; i++) { - switch (ctr->switch_value) { + switch (ctr->switch_value) { case 0x01: - display_dfs_info_1(&ctr->dfs.info1[i]); + display_dfs_info_1(&ctr->u.info1); break; case 0x02: - display_dfs_info_2(&ctr->dfs.info2[i]); + display_dfs_info_2(&ctr->u.info2); break; case 0x03: - display_dfs_info_3(&ctr->dfs.info3[i]); + display_dfs_info_3(&ctr->u.info3); break; default: printf("unsupported info level %d\n", ctr->switch_value); break; + } +} + +static void display_dfs_enumstruct(NETDFS_DFS_ENUMSTRUCT *ctr) +{ + int i; + + /* count is always the first element, so we can just use info1 here */ + for (i = 0; i < ctr->e.u.info1.count; i++) { + switch (ctr->level) { + case 1: display_dfs_info_1(&ctr->e.u.info1.s[i]); break; + case 2: display_dfs_info_2(&ctr->e.u.info2.s[i]); break; + case 3: display_dfs_info_3(&ctr->e.u.info3.s[i]); break; + default: + printf("unsupported info level %d\n", + ctr->level); + return; } } } @@ -171,9 +186,11 @@ static void display_dfs_info_ctr(DFS_INFO_CTR *ctr) static NTSTATUS cmd_dfs_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { - DFS_INFO_CTR ctr; + NETDFS_DFS_ENUMSTRUCT str; + NETDFS_DFS_ENUMINFO_CTR ctr; NTSTATUS result; uint32 info_level = 1; + uint32 unknown = 0, total = 0; if (argc > 2) { printf("Usage: %s [info_level]\n", argv[0]); @@ -183,10 +200,14 @@ static NTSTATUS cmd_dfs_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, if (argc == 2) info_level = atoi(argv[1]); - result = rpccli_dfs_enum(cli, mem_ctx, info_level, &ctr); + ZERO_STRUCT(ctr); + init_netdfs_dfs_EnumStruct(&str, info_level, ctr); + str.e.ptr0 = 1; + + result = rpccli_dfs_Enum(cli, mem_ctx, info_level, 0xFFFFFFFF, &str, &unknown, &total); if (NT_STATUS_IS_OK(result)) - display_dfs_info_ctr(&ctr); + display_dfs_enumstruct(&str); return result; } @@ -195,28 +216,28 @@ static NTSTATUS cmd_dfs_getinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx int argc, const char **argv) { NTSTATUS result; - const char *entrypath, *servername, *sharename; + const char *path, *servername, *sharename; uint32 info_level = 1; - DFS_INFO_CTR ctr; + NETDFS_DFS_INFO_CTR ctr; if (argc < 4 || argc > 5) { - printf("Usage: %s entrypath servername sharename " + printf("Usage: %s path servername sharename " "[info_level]\n", argv[0]); return NT_STATUS_OK; } - entrypath = argv[1]; + path = argv[1]; servername = argv[2]; sharename = argv[3]; if (argc == 5) info_level = atoi(argv[4]); - result = rpccli_dfs_get_info(cli, mem_ctx, entrypath, servername, + result = rpccli_dfs_GetInfo(cli, mem_ctx, path, servername, sharename, info_level, &ctr); if (NT_STATUS_IS_OK(result)) - display_dfs_info_ctr(&ctr); + display_dfs_info(&ctr); return result; } diff --git a/source/rpcclient/cmd_lsarpc.c b/source/rpcclient/cmd_lsarpc.c index 5adaf469818..1b7ebac45f9 100644 --- a/source/rpcclient/cmd_lsarpc.c +++ b/source/rpcclient/cmd_lsarpc.c @@ -47,7 +47,7 @@ static NTSTATUS name_to_sid(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(result)) goto done; - result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, 1, &name, &sids, &sid_types); + result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, 1, &name, NULL, &sids, &sid_types); if (!NT_STATUS_IS_OK(result)) goto done; @@ -165,7 +165,7 @@ static NTSTATUS cmd_lsa_lookup_names(struct rpc_pipe_client *cli, goto done; result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 1, - (const char**)(argv + 1), &sids, &types); + (const char**)(argv + 1), NULL, &sids, &types); if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED)) diff --git a/source/rpcclient/cmd_samr.c b/source/rpcclient/cmd_samr.c index 991b55a13c8..93a3e390363 100644 --- a/source/rpcclient/cmd_samr.c +++ b/source/rpcclient/cmd_samr.c @@ -1065,6 +1065,82 @@ static NTSTATUS cmd_samr_query_aliasmem(struct rpc_pipe_client *cli, return result; } +/* Query delete an alias membership */ + +static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 alias_rid; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if (argc != 3) { + printf("Usage: %s builtin|domain [rid|name]\n", argv[0]); + return NT_STATUS_OK; + } + + alias_rid = strtoul(argv[2], NULL, 10); + + /* Open SAMR handle */ + + result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on domain */ + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &global_sid_Builtin, &domain_pol); + else + return NT_STATUS_INVALID_PARAMETER; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on alias */ + + result = rpccli_samr_open_alias(cli, mem_ctx, &domain_pol, + access_mask, + alias_rid, &alias_pol); + if (!NT_STATUS_IS_OK(result) && (alias_rid == 0)) { + /* Probably this was a user name, try lookupnames */ + uint32 num_rids; + uint32 *rids, *types; + + result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol, + 1000, 1, &argv[2], + &num_rids, &rids, + &types); + + if (NT_STATUS_IS_OK(result)) { + result = rpccli_samr_open_alias(cli, mem_ctx, + &domain_pol, + access_mask, + rids[0], &alias_pol); + } + } + + result = rpccli_samr_delete_dom_alias(cli, mem_ctx, &alias_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rpccli_samr_close(cli, mem_ctx, &domain_pol); + rpccli_samr_close(cli, mem_ctx, &connect_pol); + done: + return result; +} + /* Query display info */ static NTSTATUS cmd_samr_query_dispinfo(struct rpc_pipe_client *cli, @@ -1405,6 +1481,65 @@ static NTSTATUS cmd_samr_create_dom_group(struct rpc_pipe_client *cli, return result; } +/* Create domain alias */ + +static NTSTATUS cmd_samr_create_dom_alias(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *alias_name; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s aliasname [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + alias_name = argv[1]; + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol, + access_mask, + &domain_sid, &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Create domain user */ + + result = rpccli_samr_create_dom_alias(cli, mem_ctx, &domain_pol, + alias_name, &alias_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_close(cli, mem_ctx, &alias_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + /* Lookup sam names */ static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli, @@ -1793,6 +1928,7 @@ struct cmd_set samr_commands[] = { { "queryuseraliases", RPC_RTYPE_NTSTATUS, cmd_samr_query_useraliases, NULL, PI_SAMR, NULL, "Query user aliases", "" }, { "querygroupmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_groupmem, NULL, PI_SAMR, NULL, "Query group membership", "" }, { "queryaliasmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasmem, NULL, PI_SAMR, NULL, "Query alias membership", "" }, + { "deletealias", RPC_RTYPE_NTSTATUS, cmd_samr_delete_alias, NULL, PI_SAMR, NULL, "Delete an alias", "" }, { "querydispinfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo, NULL, PI_SAMR, NULL, "Query display info", "" }, { "querydominfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dominfo, NULL, PI_SAMR, NULL, "Query domain info", "" }, { "enumdomusers", RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_users, NULL, PI_SAMR, NULL, "Enumerate domain users", "" }, @@ -1801,6 +1937,7 @@ struct cmd_set samr_commands[] = { { "createdomuser", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_user, NULL, PI_SAMR, NULL, "Create domain user", "" }, { "createdomgroup", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_group, NULL, PI_SAMR, NULL, "Create domain group", "" }, + { "createdomalias", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_alias, NULL, PI_SAMR, NULL, "Create domain alias", "" }, { "samlookupnames", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_names, NULL, PI_SAMR, NULL, "Look up names", "" }, { "samlookuprids", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_rids, NULL, PI_SAMR, NULL, "Look up names", "" }, { "deletedomuser", RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_user, NULL, PI_SAMR, NULL, "Delete domain user", "" }, diff --git a/source/sam/idmap.c b/source/sam/idmap.c index 9fc1a573a92..aac8b70013a 100644 --- a/source/sam/idmap.c +++ b/source/sam/idmap.c @@ -188,6 +188,18 @@ NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) if (proxyonly) return NT_STATUS_UNSUCCESSFUL; + if (sid_check_is_in_our_domain(sid)) { + DEBUG(3, ("Refusing to add SID %s to idmap, it's our own " + "domain\n", sid_string_static(sid))); + return NT_STATUS_ACCESS_DENIED; + } + + if (sid_check_is_in_builtin(sid)) { + DEBUG(3, ("Refusing to add SID %s to idmap, it's our builtin " + "domain\n", sid_string_static(sid))); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n", sid_string_static(sid), ((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID", @@ -225,6 +237,18 @@ NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid) if (proxyonly) return NT_STATUS_UNSUCCESSFUL; + if (sid_check_is_in_our_domain(sid)) { + DEBUG(9, ("sid %s is in our domain -- go look in passdb\n", + sid_string_static(sid))); + return NT_STATUS_NONE_MAPPED; + } + + if (sid_check_is_in_builtin(sid)) { + DEBUG(9, ("sid %s is in builtin domain -- go look in passdb\n", + sid_string_static(sid))); + return NT_STATUS_NONE_MAPPED; + } + loc_type = *id_type; if (remote_map) { @@ -337,23 +361,6 @@ NTSTATUS idmap_allocate_id(unid_t *id, int id_type) return cache_map->allocate_id( id, id_type ); } -/************************************************************************** - Alloocate a new RID -**************************************************************************/ - -NTSTATUS idmap_allocate_rid(uint32 *rid, int type) -{ - /* we have to allocate from the authoritative backend */ - - if (proxyonly) - return NT_STATUS_UNSUCCESSFUL; - - if ( remote_map ) - return remote_map->allocate_rid( rid, type ); - - return cache_map->allocate_rid( rid, type ); -} - /************************************************************************** Shutdown maps. **************************************************************************/ diff --git a/source/sam/idmap_ad.c b/source/sam/idmap_ad.c index 47e349483dd..f9a959e7ec0 100644 --- a/source/sam/idmap_ad.c +++ b/source/sam/idmap_ad.c @@ -371,12 +371,6 @@ static NTSTATUS ad_idmap_close(void) return NT_STATUS_OK; } -/* New for beta3 */ -static NTSTATUS ad_idmap_allocate_rid(uint32 *rid, int rid_type) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - static NTSTATUS ad_idmap_allocate_id(unid_t *id, int id_type) { return NT_STATUS_NOT_IMPLEMENTED; @@ -389,7 +383,6 @@ static void ad_idmap_status(void) static struct idmap_methods ad_methods = { ad_idmap_init, - ad_idmap_allocate_rid, ad_idmap_allocate_id, ad_idmap_get_sid_from_id, ad_idmap_get_id_from_sid, diff --git a/source/sam/idmap_ldap.c b/source/sam/idmap_ldap.c index b4a8c8a7528..17482a5146d 100644 --- a/source/sam/idmap_ldap.c +++ b/source/sam/idmap_ldap.c @@ -113,260 +113,6 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) return NT_STATUS_OK; } -/********************************************************************** - Even if the sambaDomain attribute in LDAP tells us that this RID is - safe to use, always check before use. -*********************************************************************/ - -static BOOL sid_in_use(struct ldap_idmap_state *state, - const DOM_SID *sid, int *error) -{ - fstring filter; - fstring sid_string; - LDAPMessage *result = NULL; - int rc; - const char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL}; - - slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid)); - - rc = smbldap_search_suffix(state->smbldap_state, - filter, sid_attr, &result); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", - sid_string, ld_error)); - SAFE_FREE(ld_error); - - *error = rc; - return True; - } - - if ((ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) { - DEBUG(3, ("Sid %s already in use - trying next RID\n", - sid_string)); - ldap_msgfree(result); - return True; - } - - ldap_msgfree(result); - - /* good, sid is not in use */ - return False; -} - -/********************************************************************** - Set the new nextRid attribute, and return one we can use. - - This also checks that this RID is actually free - in case the admin - manually stole it :-). -*********************************************************************/ - -static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid, - int rid_type) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - LDAPMessage *domain_result = NULL; - LDAPMessage *entry = NULL; - char *dn; - LDAPMod **mods = NULL; - fstring old_rid_string; - fstring next_rid_string; - fstring algorithmic_rid_base_string; - uint32 next_rid; - uint32 alg_rid_base; - int attempts = 0; - char *ld_error = NULL; - - while (attempts < 10) { - if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state, - &domain_result, get_global_sam_name(), True))) { - return ret; - } - - entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result); - if (!entry) { - DEBUG(0, ("Could not get domain info entry\n")); - ldap_msgfree(domain_result); - return ret; - } - - if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) { - DEBUG(0, ("Could not get domain info DN\n")); - ldap_msgfree(domain_result); - return ret; - } - - /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and - algorithmic_rid_base. The other two are to avoid stomping on the - different sets of algorithmic RIDs */ - - if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), - algorithmic_rid_base_string)) { - - alg_rid_base = (uint32)atol(algorithmic_rid_base_string); - } else { - alg_rid_base = algorithmic_rid_base(); - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base); - smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), - algorithmic_rid_base_string); - } - - next_rid = 0; - - if (alg_rid_base > BASE_RID) { - /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we - can allocate to new users */ - if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), - old_rid_string)) { - *rid = (uint32)atol(old_rid_string); - } else { - *rid = BASE_RID; - } - - next_rid = *rid+1; - if (next_rid >= alg_rid_base) { - ldap_msgfree(domain_result); - return NT_STATUS_UNSUCCESSFUL; - } - - slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); - - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), - next_rid_string); - } - - if (!next_rid) { /* not got one already */ - switch (rid_type) { - case USER_RID_TYPE: - if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), - old_rid_string)) { - *rid = (uint32)atol(old_rid_string); - } - break; - case GROUP_RID_TYPE: - if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), - old_rid_string)) { - *rid = (uint32)atol(old_rid_string); - } - break; - } - - /* This is the core of the whole routine. If we had - scheme-style closures, there would be a *lot* less code - duplication... */ - - next_rid = *rid+RID_MULTIPLIER; - slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); - - switch (rid_type) { - case USER_RID_TYPE: - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), - next_rid_string); - break; - - case GROUP_RID_TYPE: - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), - next_rid_string); - break; - } - } - - if ((smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) { - DOM_SID dom_sid; - DOM_SID sid; - pstring domain_sid_string; - int error = 0; - - if (!smbldap_get_single_pstring(state->smbldap_state->ldap_struct, domain_result, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), - domain_sid_string)) { - ldap_mods_free(mods, True); - SAFE_FREE(dn); - ldap_msgfree(domain_result); - return ret; - } - - if (!string_to_sid(&dom_sid, domain_sid_string)) { - ldap_mods_free(mods, True); - SAFE_FREE(dn); - ldap_msgfree(domain_result); - return ret; - } - - ldap_mods_free(mods, True); - mods = NULL; - SAFE_FREE(dn); - ldap_msgfree(domain_result); - - sid_copy(&sid, &dom_sid); - sid_append_rid(&sid, *rid); - - /* check RID is not in use */ - if (sid_in_use(state, &sid, &error)) { - if (error) { - return ret; - } - continue; - } - - return NT_STATUS_OK; - } - - ld_error = NULL; - ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL")); - SAFE_FREE(ld_error); - - ldap_mods_free(mods, True); - mods = NULL; - - SAFE_FREE(dn); - - ldap_msgfree(domain_result); - domain_result = NULL; - - { - /* Sleep for a random timeout */ - unsigned sleeptime = (sys_random()*sys_getpid()*attempts); - attempts += 1; - - sleeptime %= 100; - smb_msleep(sleeptime); - } - } - - DEBUG(0, ("Failed to set new RID\n")); - return ret; -} - - -/***************************************************************************** - Allocate a new RID -*****************************************************************************/ - -static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type) -{ - return ldap_next_rid( &ldap_state, rid, rid_type ); -} - /***************************************************************************** Allocate a new uid or gid *****************************************************************************/ @@ -394,12 +140,12 @@ static NTSTATUS ldap_allocate_id(unid_t *id, int id_type) pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL); - attr_list = get_attr_list( idpool_attr_list ); + attr_list = get_attr_list( NULL, idpool_attr_list ); rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result); - free_attr_list( attr_list ); + talloc_free( attr_list ); if (rc != LDAP_SUCCESS) { DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL)); @@ -505,7 +251,7 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) LDAP_OBJ_IDMAP_ENTRY, type, ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid)); - attr_list = get_attr_list( sidmap_attr_list ); + attr_list = get_attr_list( NULL, sidmap_attr_list ); rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result); @@ -534,7 +280,7 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) ret = NT_STATUS_OK; out: - free_attr_list( attr_list ); + talloc_free( attr_list ); if (result) ldap_msgfree(result); @@ -577,7 +323,7 @@ static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *si /* do the search and check for errors */ - attr_list = get_attr_list( sidmap_attr_list ); + attr_list = get_attr_list( NULL, sidmap_attr_list ); rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result); @@ -651,7 +397,7 @@ static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *si } out: - free_attr_list( attr_list ); + talloc_free( attr_list ); if (result) ldap_msgfree(result); SAFE_FREE(dn); @@ -674,10 +420,10 @@ static NTSTATUS verify_idpool( void ) fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL ); - attr_list = get_attr_list( idpool_attr_list ); + attr_list = get_attr_list( NULL, idpool_attr_list ); rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result); - free_attr_list ( attr_list ); + talloc_free ( attr_list ); if (rc != LDAP_SUCCESS) return NT_STATUS_UNSUCCESSFUL; @@ -776,7 +522,6 @@ static void ldap_idmap_status(void) static struct idmap_methods ldap_methods = { ldap_idmap_init, - ldap_allocate_rid, ldap_allocate_id, ldap_get_sid_from_id, ldap_get_id_from_sid, diff --git a/source/sam/idmap_rid.c b/source/sam/idmap_rid.c index eced549a557..0922000fa12 100644 --- a/source/sam/idmap_rid.c +++ b/source/sam/idmap_rid.c @@ -527,11 +527,6 @@ static NTSTATUS rid_idmap_close(void) return NT_STATUS_OK; } -static NTSTATUS rid_idmap_allocate_rid(uint32 *rid, int rid_type) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - static NTSTATUS rid_idmap_allocate_id(unid_t *id, int id_type) { return NT_STATUS_NOT_IMPLEMENTED; @@ -544,7 +539,6 @@ static void rid_idmap_status(void) static struct idmap_methods rid_methods = { rid_idmap_init, - rid_idmap_allocate_rid, rid_idmap_allocate_id, rid_idmap_get_sid_from_id, rid_idmap_get_id_from_sid, diff --git a/source/sam/idmap_smbldap.c b/source/sam/idmap_smbldap.c index b1aae2b86f7..4d80364437c 100644 --- a/source/sam/idmap_smbldap.c +++ b/source/sam/idmap_smbldap.c @@ -86,15 +86,6 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) return ret; } -/***************************************************************************** - Allocate a new RID -*****************************************************************************/ - -static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type) -{ - return NT_STATUS_UNSUCCESSFUL; -} - /***************************************************************************** Allocate a new uid or gid *****************************************************************************/ @@ -437,7 +428,6 @@ static void ldap_idmap_status(void) static struct idmap_methods ldap_methods = { ldap_idmap_init, - ldap_allocate_rid, ldap_allocate_id, ldap_get_sid_from_id, ldap_get_id_from_sid, diff --git a/source/sam/idmap_tdb.c b/source/sam/idmap_tdb.c index e89a6cf547c..665c56d2f67 100644 --- a/source/sam/idmap_tdb.c +++ b/source/sam/idmap_tdb.c @@ -31,9 +31,6 @@ #define HWM_GROUP "GROUP HWM" #define HWM_USER "USER HWM" -/* idmap version determines auto-conversion */ -#define IDMAP_VERSION 2 - /* Globals */ static TDB_CONTEXT *idmap_tdb; @@ -45,41 +42,6 @@ static struct idmap_state { gid_t gid_low, gid_high; /* Range of gids to allocate */ } idmap_state; -/********************************************************************** - allocate a new RID; We don't care if is a user or group -**********************************************************************/ - -static NTSTATUS db_allocate_rid(uint32 *rid, int rid_type) -{ - uint32 lowrid, highrid; - uint32 tmp_rid; - - /* can't handle group rids right now. This is such a mess.... */ - - if ( rid_type == GROUP_RID_TYPE ) - return NT_STATUS_UNSUCCESSFUL; - - /* cannot fail since idmap is only called winbindd */ - - get_free_rid_range( &lowrid, &highrid ); - - tmp_rid = lowrid; - - if ( !tdb_change_uint32_atomic(idmap_tdb, "RID_COUNTER", &tmp_rid, RID_MULTIPLIER) ) { - DEBUG(3,("db_allocate_rid: Failed to locate next rid record in idmap db\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - if ( tmp_rid > highrid ) { - DEBUG(0, ("db_allocate_rid: no RIDs available!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - *rid = tmp_rid; - - return NT_STATUS_OK; -} - /********************************************************************** Allocate either a user or group id from the pool **********************************************************************/ @@ -660,7 +622,6 @@ TDB_CONTEXT *idmap_tdb_handle( void ) static struct idmap_methods db_methods = { db_idmap_init, - db_allocate_rid, db_allocate_id, db_get_sid_from_id, db_get_id_from_sid, diff --git a/source/sam/idmap_util.c b/source/sam/idmap_util.c index cac8934f7b6..7233cb48cd1 100644 --- a/source/sam/idmap_util.c +++ b/source/sam/idmap_util.c @@ -22,80 +22,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP -#if 0 /* NOT USED */ - -/********************************************************************** - Get the free RID base if idmap is configured, otherwise return 0 -**********************************************************************/ - -uint32 idmap_get_free_rid_base(void) -{ - uint32 low, high; - if (idmap_get_free_rid_range(&low, &high)) { - return low; - } - return 0; -} - -/********************************************************************** -**********************************************************************/ - -BOOL idmap_check_ugid_is_in_free_range(uint32 id) -{ - uint32 low, high; - - if (!idmap_get_free_ugid_range(&low, &high)) { - return False; - } - if (id < low || id > high) { - return False; - } - return True; -} - -/********************************************************************** -**********************************************************************/ - -BOOL idmap_check_rid_is_in_free_range(uint32 rid) -{ - uint32 low, high; - - if (!idmap_get_free_rid_range(&low, &high)) { - return False; - } - if (rid < algorithmic_rid_base()) { - return True; - } - - if (rid < low || rid > high) { - return False; - } - - return True; -} - -/********************************************************************** - if it is a foreign SID or if the SID is in the free range, return true -**********************************************************************/ - -BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid) -{ - if (sid_compare_domain(get_global_sam_sid(), sid) == 0) { - - uint32 rid; - - if (sid_peek_rid(sid, &rid)) { - return idmap_check_rid_is_in_free_range(rid); - } - - return False; - } - - return True; -} - -#endif /* NOT USED */ - /***************************************************************** Returns SID pointer. *****************************************************************/ diff --git a/source/script/installman.sh b/source/script/installman.sh index 9235217ff00..3bbca1a8aa5 100755 --- a/source/script/installman.sh +++ b/source/script/installman.sh @@ -19,7 +19,8 @@ if test ! -d $SRCDIR../docs/manpages; then fi # Get the configured feature set -test -f "${SRCDIR}/config.log" && eval `grep '^[A-Za-z0-9]*=.*' ${SRCDIR}/config.log` +test -f "${SRCDIR}/config.log" && \ + eval $( grep "^[[:alnum:]]*=.*" "${SRCDIR}/config.log") for lang in $langs; do if [ "X$lang" = XC ]; then @@ -43,7 +44,7 @@ for lang in $langs; do for sect in 1 5 7 8 ; do for m in $langdir/man$sect ; do for s in $SRCDIR../docs/manpages/$lang/*$sect; do - MP_BASENAME=`basename $s` + MP_BASENAME=${s##*/} # Check if this man page if required by the configured feature set case "${MP_BASENAME}" in diff --git a/source/script/installswat.sh b/source/script/installswat.sh index c66fd29485d..c5c285894e7 100755 --- a/source/script/installswat.sh +++ b/source/script/installswat.sh @@ -3,7 +3,7 @@ SWATDIR=`echo $1 | sed 's/\/\//\//g'` SRCDIR=$2/ -BOOKDIR=$SWATDIR/help/using_samba +BOOKDIR=$SWATDIR/using_samba echo Installing SWAT in $SWATDIR echo Installing the Samba Web Administration Tool @@ -14,7 +14,7 @@ echo Installing langs are `cd $SRCDIR../swat/lang/; /bin/echo ??` for ln in $LANGS; do SWATLANGDIR=$SWATDIR/$ln for d in $SWATLANGDIR $SWATLANGDIR/help $SWATLANGDIR/images \ - $SWATLANGDIR/include; do + $SWATLANGDIR/include $SWATLANGDIR/js; do if [ ! -d $d ]; then mkdir -p $d if [ ! -d $d ]; then @@ -28,7 +28,7 @@ done # Install images for ln in $LANGS; do - for f in $SRCDIR../swat/$ln/images/*.gif; do + for f in $SRCDIR../swat/$ln/images/*.png; do if [ ! -f $f ] ; then continue fi @@ -59,7 +59,7 @@ for ln in $LANGS; do # Install "server-side" includes - for f in $SRCDIR../swat/$ln/include/*.html; do + for f in $SRCDIR../swat/$ln/include/*; do if [ ! -f $f ] ; then continue fi @@ -69,6 +69,18 @@ for ln in $LANGS; do chmod 0644 $FNAME done + # Install javascripts + + for f in $SRCDIR../swat/$ln/js/*.js; do + if [ ! -f $f ] ; then + continue + fi + FNAME=$SWATDIR/$ln/js/`basename $f` + echo $FNAME + cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges? + chmod 0644 $FNAME + done + done # Install html documentation (if html documentation tree is here) diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index bb305193196..0798541cb50 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -690,7 +690,7 @@ BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar *pass2) } /* Now flush the sam_passwd struct to persistent storage */ - ret = pdb_update_sam_account (sampass); + ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass)); return ret; } @@ -828,7 +828,7 @@ static NTSTATUS check_oem_password(const char *user, DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", user)); } - pdb_free_sam(&sampass); + pdb_free_sam(&sampass); return NT_STATUS_WRONG_PASSWORD; } else { DEBUG(1, ("password change requested for user %s, but no password supplied!\n", @@ -1009,7 +1009,6 @@ static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext) NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) { - BOOL ret; uint32 min_len, min_age; struct passwd *pass = NULL; const char *username = pdb_get_username(hnd); @@ -1090,11 +1089,5 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw } /* Now write it into the file. */ - ret = pdb_update_sam_account (hnd); - - if (!ret) { - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; + return pdb_update_sam_account (hnd); } diff --git a/source/smbd/conn.c b/source/smbd/conn.c index bb000bac30e..bf4db99ea65 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -249,7 +249,7 @@ void conn_free_internal(connection_struct *conn) } if (conn->nt_user_token) { - delete_nt_token(&(conn->nt_user_token)); + talloc_free(conn->nt_user_token); } free_namearray(conn->veto_list); diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c index 4778702e7ac..83dfdf0d8bc 100644 --- a/source/smbd/lanman.c +++ b/source/smbd/lanman.c @@ -1034,107 +1034,111 @@ static int get_server_info(uint32 servertype, struct srv_info_struct **servers, const char *domain) { - int count=0; - int alloced=0; - char **lines; - BOOL local_list_only; - int i; + int count=0; + int alloced=0; + char **lines; + BOOL local_list_only; + int i; - lines = file_lines_load(lock_path(SERVER_LIST), NULL); - if (!lines) { - DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno))); - return(0); - } + lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0); + if (!lines) { + DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno))); + return 0; + } - /* request for everything is code for request all servers */ - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); + /* request for everything is code for request all servers */ + if (servertype == SV_TYPE_ALL) { + servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); + } - local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY); + local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY); - DEBUG(4,("Servertype search: %8x\n",servertype)); + DEBUG(4,("Servertype search: %8x\n",servertype)); - for (i=0;lines[i];i++) { - fstring stype; - struct srv_info_struct *s; - const char *ptr = lines[i]; - BOOL ok = True; + for (i=0;lines[i];i++) { + fstring stype; + struct srv_info_struct *s; + const char *ptr = lines[i]; + BOOL ok = True; - if (!*ptr) continue; + if (!*ptr) { + continue; + } - if (count == alloced) { - struct srv_info_struct *ts; + if (count == alloced) { + struct srv_info_struct *ts; - alloced += 10; - ts = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced); - if (!ts) { - DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n")); - return(0); - } - else *servers = ts; - memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); - } - s = &(*servers)[count]; + alloced += 10; + ts = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced); + if (!ts) { + DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n")); + return 0; + } else { + *servers = ts; + } + memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); + } + s = &(*servers)[count]; - if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue; - if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue; - if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue; - if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) { - /* this allows us to cope with an old nmbd */ - fstrcpy(s->domain,lp_workgroup()); - } + if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) { + continue; + } + if (!next_token(&ptr,stype, NULL, sizeof(stype))) { + continue; + } + if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) { + continue; + } + if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) { + /* this allows us to cope with an old nmbd */ + fstrcpy(s->domain,lp_workgroup()); + } - if (sscanf(stype,"%X",&s->type) != 1) { - DEBUG(4,("r:host file ")); - ok = False; - } + if (sscanf(stype,"%X",&s->type) != 1) { + DEBUG(4,("r:host file ")); + ok = False; + } - /* Filter the servers/domains we return based on what was asked for. */ + /* Filter the servers/domains we return based on what was asked for. */ - /* Check to see if we are being asked for a local list only. */ - if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) { - DEBUG(4,("r: local list only")); - ok = False; - } + /* Check to see if we are being asked for a local list only. */ + if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) { + DEBUG(4,("r: local list only")); + ok = False; + } - /* doesn't match up: don't want it */ - if (!(servertype & s->type)) { - DEBUG(4,("r:serv type ")); - ok = False; - } + /* doesn't match up: don't want it */ + if (!(servertype & s->type)) { + DEBUG(4,("r:serv type ")); + ok = False; + } - if ((servertype & SV_TYPE_DOMAIN_ENUM) != - (s->type & SV_TYPE_DOMAIN_ENUM)) - { - DEBUG(4,("s: dom mismatch ")); - ok = False; - } + if ((servertype & SV_TYPE_DOMAIN_ENUM) != + (s->type & SV_TYPE_DOMAIN_ENUM)) { + DEBUG(4,("s: dom mismatch ")); + ok = False; + } - if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - { - ok = False; - } + if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) { + ok = False; + } - /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */ - s->type &= ~SV_TYPE_LOCAL_LIST_ONLY; + /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */ + s->type &= ~SV_TYPE_LOCAL_LIST_ONLY; - if (ok) - { - DEBUG(4,("**SV** %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - - s->server_added = True; - count++; - } - else - { - DEBUG(4,("%20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - } - } + if (ok) { + DEBUG(4,("**SV** %20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + s->server_added = True; + count++; + } else { + DEBUG(4,("%20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + } + } - file_lines_free(lines); - return(count); + file_lines_free(lines); + return count; } /******************************************************************* @@ -1145,75 +1149,79 @@ static int fill_srv_info(struct srv_info_struct *service, int uLevel, char **buf, int *buflen, char **stringbuf, int *stringspace, char *baseaddr) { - int struct_len; - char* p; - char* p2; - int l2; - int len; + int struct_len; + char* p; + char* p2; + int l2; + int len; - switch (uLevel) { - case 0: struct_len = 16; break; - case 1: struct_len = 26; break; - default: return -1; - } - - if (!buf) - { - len = 0; - switch (uLevel) - { - case 1: - len = strlen(service->comment)+1; - break; + switch (uLevel) { + case 0: + struct_len = 16; + break; + case 1: + struct_len = 26; + break; + default: + return -1; } + + if (!buf) { + len = 0; + switch (uLevel) { + case 1: + len = strlen(service->comment)+1; + break; + } - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } + if (buflen) { + *buflen = struct_len; + } + if (stringspace) { + *stringspace = len; + } + return struct_len + len; + } - len = struct_len; - p = *buf; - if (*buflen < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = *buflen - struct_len; - } - if (!baseaddr) baseaddr = p; + len = struct_len; + p = *buf; + if (*buflen < struct_len) { + return -1; + } + if (stringbuf) { + p2 = *stringbuf; + l2 = *stringspace; + } else { + p2 = p + struct_len; + l2 = *buflen - struct_len; + } + if (!baseaddr) { + baseaddr = p; + } - switch (uLevel) - { - case 0: - push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE); - break; - - case 1: - push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE); - SIVAL(p,18,service->type); - SIVAL(p,22,PTR_DIFF(p2,baseaddr)); - len += CopyAndAdvance(&p2,service->comment,&l2); - break; - } - - if (stringbuf) - { - *buf = p + struct_len; - *buflen -= struct_len; - *stringbuf = p2; - *stringspace = l2; - } - else - { - *buf = p2; - *buflen -= len; - } - return len; + switch (uLevel) { + case 0: + push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE); + break; + + case 1: + push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE); + SIVAL(p,18,service->type); + SIVAL(p,22,PTR_DIFF(p2,baseaddr)); + len += CopyAndAdvance(&p2,service->comment,&l2); + break; + } + + if (stringbuf) { + *buf = p + struct_len; + *buflen -= struct_len; + *stringbuf = p2; + *stringspace = l2; + } else { + *buf = p2; + *buflen -= len; + } + return len; } @@ -1231,124 +1239,137 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param int mdrcnt, int mprcnt, char **rdata, char **rparam, int *rdata_len, int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - uint32 servertype = IVAL(p,4); - char *p2; - int data_len, fixed_len, string_len; - int f_len = 0, s_len = 0; - struct srv_info_struct *servers=NULL; - int counted=0,total=0; - int i,missed; - fstring domain; - BOOL domain_request; - BOOL local_request; - - /* If someone sets all the bits they don't really mean to set - DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the - known servers. */ - - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); - - /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set - any other bit (they may just set this bit on it's own) they - want all the locally seen servers. However this bit can be - set on its own so set the requested servers to be - ALL - DOMAIN_ENUM. */ - - if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); - - domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); - local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); - - p += 8; - - if (!prefix_ok(str1,"WrLehD")) return False; - if (!check_server_info(uLevel,str2)) return False; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + int buf_len = SVAL(p,2); + uint32 servertype = IVAL(p,4); + char *p2; + int data_len, fixed_len, string_len; + int f_len = 0, s_len = 0; + struct srv_info_struct *servers=NULL; + int counted=0,total=0; + int i,missed; + fstring domain; + BOOL domain_request; + BOOL local_request; + + /* If someone sets all the bits they don't really mean to set + DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the + known servers. */ + + if (servertype == SV_TYPE_ALL) { + servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); + } + + /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set + any other bit (they may just set this bit on it's own) they + want all the locally seen servers. However this bit can be + set on its own so set the requested servers to be + ALL - DOMAIN_ENUM. */ + + if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) { + servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); + } + + domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); + local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); + + p += 8; + + if (!prefix_ok(str1,"WrLehD")) { + return False; + } + if (!check_server_info(uLevel,str2)) { + return False; + } - DEBUG(4, ("server request level: %s %8x ", str2, servertype)); - DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); - DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); - - if (strcmp(str1, "WrLehDz") == 0) { - pull_ascii_fstring(domain, p); - } else { - fstrcpy(domain, lp_workgroup()); - } - - if (lp_browse_list()) - total = get_server_info(servertype,&servers,domain); - - data_len = fixed_len = string_len = 0; - missed = 0; - - if (total > 0) - qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); - - { - char *lastname=NULL; - - for (i=0;iname)) continue; - lastname = s->name; - data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); + DEBUG(4, ("server request level: %s %8x ", str2, servertype)); + DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); + DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); + + if (strcmp(str1, "WrLehDz") == 0) { + pull_ascii_fstring(domain, p); + } else { + fstrcpy(domain, lp_workgroup()); + } + + if (lp_browse_list()) { + total = get_server_info(servertype,&servers,domain); + } + + data_len = fixed_len = string_len = 0; + missed = 0; + + if (total > 0) { + qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); + } + + { + char *lastname=NULL; + + for (i=0;iname)) { + continue; + } + lastname = s->name; + data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); + DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); - if (data_len <= buf_len) { - counted++; - fixed_len += f_len; - string_len += s_len; - } else { - missed++; - } - } - } - - *rdata_len = fixed_len + string_len; - *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); - memset(*rdata,'\0',*rdata_len); + if (data_len <= buf_len) { + counted++; + fixed_len += f_len; + string_len += s_len; + } else { + missed++; + } + } + } + + *rdata_len = fixed_len + string_len; + *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); + memset(*rdata,'\0',*rdata_len); - p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - - { - char *lastname=NULL; - int count2 = counted; - for (i = 0; i < total && count2;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) continue; - lastname = s->name; - fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - count2--; - } - } + p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */ + p = *rdata; + f_len = fixed_len; + s_len = string_len; + + { + char *lastname=NULL; + int count2 = counted; + + for (i = 0; i < total && count2;i++) { + struct srv_info_struct *s = &servers[i]; + + if (lastname && strequal(lastname,s->name)) { + continue; + } + lastname = s->name; + fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); + DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + count2--; + } + } - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata)); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,counted+missed); + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata)); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,counted); + SSVAL(*rparam,6,counted+missed); - SAFE_FREE(servers); + SAFE_FREE(servers); - DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", - domain,uLevel,counted,counted+missed)); + DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", + domain,uLevel,counted,counted+missed)); - return(True); + return True; } /**************************************************************************** @@ -1359,30 +1380,32 @@ static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *pa int mdrcnt, int mprcnt, char **rdata, char **rparam, int *rdata_len, int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - int counted=0; - int missed=0; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + int buf_len = SVAL(p,2); + int counted=0; + int missed=0; DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n", str1, str2, p, uLevel, buf_len)); - if (!prefix_ok(str1,"zWrLeh")) return False; + if (!prefix_ok(str1,"zWrLeh")) { + return False; + } - *rdata_len = 0; + *rdata_len = 0; - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,0x08AC); /* informational warning message */ - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,counted+missed); + SSVAL(*rparam,0,0x08AC); /* informational warning message */ + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,counted); + SSVAL(*rparam,6,counted+missed); - return(True); + return True; } /**************************************************************************** @@ -1391,117 +1414,146 @@ static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *pa static BOOL check_share_info(int uLevel, char* id) { - switch( uLevel ) { - case 0: - if (strcmp(id,"B13") != 0) return False; - break; - case 1: - if (strcmp(id,"B13BWz") != 0) return False; - break; - case 2: - if (strcmp(id,"B13BWzWWWzB9B") != 0) return False; - break; - case 91: - if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False; - break; - default: return False; - } - return True; + switch( uLevel ) { + case 0: + if (strcmp(id,"B13") != 0) { + return False; + } + break; + case 1: + if (strcmp(id,"B13BWz") != 0) { + return False; + } + break; + case 2: + if (strcmp(id,"B13BWzWWWzB9B") != 0) { + return False; + } + break; + case 91: + if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) { + return False; + } + break; + default: + return False; + } + return True; } static int fill_share_info(connection_struct *conn, int snum, int uLevel, char** buf, int* buflen, char** stringbuf, int* stringspace, char* baseaddr) { - int struct_len; - char* p; - char* p2; - int l2; - int len; + int struct_len; + char* p; + char* p2; + int l2; + int len; - switch( uLevel ) { - case 0: struct_len = 13; break; - case 1: struct_len = 20; break; - case 2: struct_len = 40; break; - case 91: struct_len = 68; break; - default: return -1; - } + switch( uLevel ) { + case 0: + struct_len = 13; + break; + case 1: + struct_len = 20; + break; + case 2: + struct_len = 40; + break; + case 91: + struct_len = 68; + break; + default: + return -1; + } - if (!buf) - { - len = 0; - if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum)); - if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1; - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } + if (!buf) { + len = 0; + + if (uLevel > 0) { + len += StrlenExpanded(conn,snum,lp_comment(snum)); + } + if (uLevel > 1) { + len += strlen(lp_pathname(snum)) + 1; + } + if (buflen) { + *buflen = struct_len; + } + if (stringspace) { + *stringspace = len; + } + return struct_len + len; + } - len = struct_len; - p = *buf; - if ((*buflen) < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = (*buflen) - struct_len; - } - if (!baseaddr) baseaddr = p; + len = struct_len; + p = *buf; + if ((*buflen) < struct_len) { + return -1; + } + + if (stringbuf) { + p2 = *stringbuf; + l2 = *stringspace; + } else { + p2 = p + struct_len; + l2 = (*buflen) - struct_len; + } + + if (!baseaddr) { + baseaddr = p; + } - push_ascii(p,lp_servicename(snum),13, STR_TERMINATE); + push_ascii(p,lp_servicename(snum),13, STR_TERMINATE); - if (uLevel > 0) - { - int type; - SCVAL(p,13,0); - type = STYPE_DISKTREE; - if (lp_print_ok(snum)) type = STYPE_PRINTQ; - if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC; - SSVAL(p,14,type); /* device type */ - SIVAL(p,16,PTR_DIFF(p2,baseaddr)); - len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2); - } + if (uLevel > 0) { + int type; + + SCVAL(p,13,0); + type = STYPE_DISKTREE; + if (lp_print_ok(snum)) { + type = STYPE_PRINTQ; + } + if (strequal("IPC",lp_fstype(snum))) { + type = STYPE_IPC; + } + SSVAL(p,14,type); /* device type */ + SIVAL(p,16,PTR_DIFF(p2,baseaddr)); + len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2); + } - if (uLevel > 1) - { - SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */ - SSVALS(p,22,-1); /* max uses */ - SSVAL(p,24,1); /* current uses */ - SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */ - len += CopyAndAdvance(&p2,lp_pathname(snum),&l2); - memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */ - } + if (uLevel > 1) { + SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */ + SSVALS(p,22,-1); /* max uses */ + SSVAL(p,24,1); /* current uses */ + SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */ + len += CopyAndAdvance(&p2,lp_pathname(snum),&l2); + memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */ + } - if (uLevel > 2) - { - memset(p+40,0,SHPWLEN+2); - SSVAL(p,50,0); - SIVAL(p,52,0); - SSVAL(p,56,0); - SSVAL(p,58,0); - SIVAL(p,60,0); - SSVAL(p,64,0); - SSVAL(p,66,0); - } + if (uLevel > 2) { + memset(p+40,0,SHPWLEN+2); + SSVAL(p,50,0); + SIVAL(p,52,0); + SSVAL(p,56,0); + SSVAL(p,58,0); + SIVAL(p,60,0); + SSVAL(p,64,0); + SSVAL(p,66,0); + } - if (stringbuf) - { - (*buf) = p + struct_len; - (*buflen) -= struct_len; - (*stringbuf) = p2; - (*stringspace) = l2; - } - else - { - (*buf) = p2; - (*buflen) -= len; - } - return len; + if (stringbuf) { + (*buf) = p + struct_len; + (*buflen) -= struct_len; + (*stringbuf) = p2; + (*stringspace) = l2; + } else { + (*buf) = p2; + (*buflen) -= len; + } + + return len; } static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -1509,31 +1561,39 @@ static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *para char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *netname = skip_string(str2,1); - char *p = skip_string(netname,1); - int uLevel = SVAL(p,0); - int snum = find_service(netname); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *netname = skip_string(str2,1); + char *p = skip_string(netname,1); + int uLevel = SVAL(p,0); + int snum = find_service(netname); - if (snum < 0) return False; + if (snum < 0) { + return False; + } - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) return False; - if (!check_share_info(uLevel,str2)) return False; + /* check it's a supported varient */ + if (!prefix_ok(str1,"zWrLh")) { + return False; + } + if (!check_share_info(uLevel,str2)) { + return False; + } - *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - p = *rdata; - *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0); - if (*rdata_len < 0) return False; + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + p = *rdata; + *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0); + if (*rdata_len < 0) { + return False; + } - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,*rdata_len); - return(True); + return True; } /**************************************************************************** @@ -1557,78 +1617,87 @@ static BOOL api_RNetShareEnum( connection_struct *conn, int *rdata_len, int *rparam_len ) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - char *p2; - int count=lp_numservices(); - int total=0,counted=0; - BOOL missed = False; - int i; - int data_len, fixed_len, string_len; - int f_len = 0, s_len = 0; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + int buf_len = SVAL(p,2); + char *p2; + int count = 0; + int total=0,counted=0; + BOOL missed = False; + int i; + int data_len, fixed_len, string_len; + int f_len = 0, s_len = 0; - if (!prefix_ok(str1,"WrLeh")) return False; - if (!check_share_info(uLevel,str2)) return False; + if (!prefix_ok(str1,"WrLeh")) { + return False; + } + if (!check_share_info(uLevel,str2)) { + return False; + } - data_len = fixed_len = string_len = 0; - for (i=0;i= 0) { /* already exists */ - res = ERRfilexists; - goto error_exit; - } - - /* only support disk share adds */ - if (SVAL(data,14)!=STYPE_DISKTREE) return False; - - offset = IVAL(data, 16); - if (offset >= mdrcnt) { - res = ERRinvalidparam; - goto error_exit; - } - pull_ascii_fstring(comment, offset? (data+offset) : ""); - - offset = IVAL(data, 26); - if (offset >= mdrcnt) { - res = ERRinvalidparam; - goto error_exit; - } - pull_ascii_pstring(pathname, offset? (data+offset) : ""); - - string_replace(sharename, '"', ' '); - string_replace(pathname, '"', ' '); - string_replace(comment, '"', ' '); - - cmdname = lp_add_share_cmd(); - - if (!cmdname || *cmdname == '\0') return False; - - asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"", - lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment); - - if (command) { - DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command )); - if ((res = smbrun(command, NULL)) != 0) { - DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res )); - SAFE_FREE(command); - res = ERRnoaccess; - goto error_exit; - } else { - SAFE_FREE(command); - message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL); - } - } else return False; - - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - *rdata_len = 0; - - return True; - - error_exit: - *rparam_len = 4; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - *rdata_len = 0; - SSVAL(*rparam,0,res); - SSVAL(*rparam,2,0); - return True; -} - -/**************************************************************************** - view list of groups available - ****************************************************************************/ - -static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - int i; - int errflags=0; - int resume_context, cli_buf_size; char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + fstring sharename; + fstring comment; + pstring pathname; + char *command, *cmdname; + unsigned int offset; + int snum; + int res = ERRunsup; + + /* check it's a supported varient */ + if (!prefix_ok(str1,RAP_WShareAdd_REQ)) { + return False; + } + if (!check_share_info(uLevel,str2)) { + return False; + } + if (uLevel != 2) { + return False; + } - struct pdb_search *search; - struct samr_displayentry *entries; + pull_ascii_fstring(sharename,data); + snum = find_service(sharename); + if (snum >= 0) { /* already exists */ + res = ERRfilexists; + goto error_exit; + } - int num_entries; - - if (strcmp(str1,"WrLeh") != 0) + /* only support disk share adds */ + if (SVAL(data,14)!=STYPE_DISKTREE) { return False; + } - /* parameters - * W-> resume context (number of users to skip) - * r -> return parameter pointer to receive buffer - * L -> length of receive buffer - * e -> return parameter number of entries - * h -> return parameter total number of users - */ - if (strcmp("B21",str2) != 0) - return False; + offset = IVAL(data, 16); + if (offset >= mdrcnt) { + res = ERRinvalidparam; + goto error_exit; + } + + pull_ascii_fstring(comment, offset? (data+offset) : ""); + + offset = IVAL(data, 26); + + if (offset >= mdrcnt) { + res = ERRinvalidparam; + goto error_exit; + } + + pull_ascii_pstring(pathname, offset? (data+offset) : ""); + + string_replace(sharename, '"', ' '); + string_replace(pathname, '"', ' '); + string_replace(comment, '"', ' '); + + cmdname = lp_add_share_cmd(); + + if (!cmdname || *cmdname == '\0') { + return False; + } + + asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"", + lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment); + + if (command) { + DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command )); + + if ((res = smbrun(command, NULL)) != 0) { + DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res )); + SAFE_FREE(command); + res = ERRnoaccess; + goto error_exit; + } else { + SAFE_FREE(command); + message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL); + } + } else { + return False; + } + + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,*rdata_len); + *rdata_len = 0; + + return True; + + error_exit: + + *rparam_len = 4; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + *rdata_len = 0; + SSVAL(*rparam,0,res); + SSVAL(*rparam,2,0); + return True; +} + +/**************************************************************************** + view list of groups available + ****************************************************************************/ + +static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) +{ + int i; + int errflags=0; + int resume_context, cli_buf_size; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + + struct pdb_search *search; + struct samr_displayentry *entries; + + int num_entries; + + if (strcmp(str1,"WrLeh") != 0) { + return False; + } + + /* parameters + * W-> resume context (number of users to skip) + * r -> return parameter pointer to receive buffer + * L -> length of receive buffer + * e -> return parameter number of entries + * h -> return parameter total number of users + */ + + if (strcmp("B21",str2) != 0) { + return False; + } /* get list of domain groups SID_DOMAIN_GRP=2 */ become_root(); @@ -1837,8 +1926,10 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para gid_t *gids; size_t num_groups; size_t i; - struct passwd *passwd; NTSTATUS result; + DOM_SID user_sid; + enum SID_NAME_USE type; + TALLOC_CTX *mem_ctx; *rparam_len = 8; *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); @@ -1867,45 +1958,64 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para p = *rdata; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + /* Lookup the user information; This should only be one of our accounts (not remote domains) */ - passwd = getpwnam_alloc(UserName); - - if (passwd == NULL) - return False; - - pdb_init_sam( &sampw ); - become_root(); /* ROOT BLOCK */ - if ( !pdb_getsampwnam(sampw, UserName) ) - goto out; + if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL, + NULL, NULL, &user_sid, &type)) { + DEBUG(10, ("lookup_name(%s) failed\n", UserName)); + goto done; + } + + if (type != SID_NAME_USER) { + DEBUG(10, ("%s is a %s, not a user\n", UserName, + sid_type_lookup(type))); + goto done; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam_talloc(mem_ctx, &sampw))) { + DEBUG(10, ("pdb_init_sam_talloc failed\n")); + goto done; + } + + if ( !pdb_getsampwsid(sampw, &user_sid) ) { + DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n", + sid_string_static(&user_sid), UserName)); + goto done; + } + gids = NULL; sids = NULL; num_groups = 0; - result = pdb_enum_group_memberships(pdb_get_username(sampw), - passwd->pw_gid, + result = pdb_enum_group_memberships(mem_ctx, sampw, &sids, &gids, &num_groups); - if (!NT_STATUS_IS_OK(result)) - goto out; + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_enum_group_memberships failed for %s\n", + UserName)); + goto done; + } for (i=0; imem_ctx, &sids[i], NULL, &grp_name, - NULL) ) { + if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) { pstrcpy(p, grp_name); p += 21; count++; } } - SAFE_FREE(sids); - *rdata_len = PTR_DIFF(p,*rdata); SSVAL(*rparam,4,count); /* is this right?? */ @@ -1913,11 +2023,10 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para ret = True; -out: +done: unbecome_root(); /* END ROOT BLOCK */ - pdb_free_sam( &sampw ); - passwd_free(&passwd); + talloc_free(mem_ctx); return ret; } @@ -2023,43 +2132,42 @@ static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,ch char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *p; - *rparam_len = 4; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - - *rdata_len = 21; - *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - { - struct tm *t; - time_t unixdate = time(NULL); - - srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at - by NT in a "net time" operation, - it seems to ignore the one below */ - - /* the client expects to get localtime, not GMT, in this bit - (I think, this needs testing) */ - t = localtime(&unixdate); - - SIVAL(p,4,0); /* msecs ? */ - SCVAL(p,8,t->tm_hour); - SCVAL(p,9,t->tm_min); - SCVAL(p,10,t->tm_sec); - SCVAL(p,11,0); /* hundredths of seconds */ - SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */ - SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ - SCVAL(p,16,t->tm_mday); - SCVAL(p,17,t->tm_mon + 1); - SSVAL(p,18,1900+t->tm_year); - SCVAL(p,20,t->tm_wday); - } - return(True); + struct tm *t; + time_t unixdate = time(NULL); + char *p; + + *rparam_len = 4; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + + *rdata_len = 21; + *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); + + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + + p = *rdata; + + srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at + by NT in a "net time" operation, + it seems to ignore the one below */ + + /* the client expects to get localtime, not GMT, in this bit + (I think, this needs testing) */ + t = localtime(&unixdate); + + SIVAL(p,4,0); /* msecs ? */ + SCVAL(p,8,t->tm_hour); + SCVAL(p,9,t->tm_min); + SCVAL(p,10,t->tm_sec); + SCVAL(p,11,0); /* hundredths of seconds */ + SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */ + SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ + SCVAL(p,16,t->tm_mday); + SCVAL(p,17,t->tm_mon + 1); + SSVAL(p,18,1900+t->tm_year); + SCVAL(p,20,t->tm_wday); + + return True; } /**************************************************************************** @@ -2111,7 +2219,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param } unbecome_root(); - free_server_info(&server_info); + talloc_free(server_info); } data_blob_clear_free(&password); } @@ -2421,103 +2529,117 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - char *p2; - int struct_len; - - DEBUG(4,("NetServerGetInfo level %d\n",uLevel)); - - /* check it's a supported varient */ - if (!prefix_ok(str1,"WrLh")) return False; - switch( uLevel ) { - case 0: - if (strcmp(str2,"B16") != 0) return False; - struct_len = 16; - break; - case 1: - if (strcmp(str2,"B16BBDz") != 0) return False; - struct_len = 26; - break; - case 2: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz") - != 0) return False; - struct_len = 134; - break; - case 3: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") - != 0) return False; - struct_len = 144; - break; - case 20: - if (strcmp(str2,"DN") != 0) return False; - struct_len = 6; - break; - case 50: - if (strcmp(str2,"B16BBDzWWzzz") != 0) return False; - struct_len = 42; - break; - default: return False; - } - - *rdata_len = mdrcnt; - *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); - - p = *rdata; - p2 = p + struct_len; - if (uLevel != 20) { - srvstr_push(NULL, p,get_local_machine_name(),16, - STR_ASCII|STR_UPPER|STR_TERMINATE); - } - p += 16; - if (uLevel > 0) - { - struct srv_info_struct *servers=NULL; - int i,count; - pstring comment; - uint32 servertype= lp_default_server_announce(); - - push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE); - - if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { - for (i=0;i 1) - { - return False; /* not yet implemented */ - } - - *rdata_len = PTR_DIFF(p2,*rdata); - - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - - return(True); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + char *p2; + int struct_len; + + DEBUG(4,("NetServerGetInfo level %d\n",uLevel)); + + /* check it's a supported varient */ + if (!prefix_ok(str1,"WrLh")) { + return False; + } + + switch( uLevel ) { + case 0: + if (strcmp(str2,"B16") != 0) { + return False; + } + struct_len = 16; + break; + case 1: + if (strcmp(str2,"B16BBDz") != 0) { + return False; + } + struct_len = 26; + break; + case 2: + if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) { + return False; + } + struct_len = 134; + break; + case 3: + if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) { + return False; + } + struct_len = 144; + break; + case 20: + if (strcmp(str2,"DN") != 0) { + return False; + } + struct_len = 6; + break; + case 50: + if (strcmp(str2,"B16BBDzWWzzz") != 0) { + return False; + } + struct_len = 42; + break; + default: + return False; + } + + *rdata_len = mdrcnt; + *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); + + p = *rdata; + p2 = p + struct_len; + if (uLevel != 20) { + srvstr_push(NULL, p,get_local_machine_name(),16, + STR_ASCII|STR_UPPER|STR_TERMINATE); + } + p += 16; + if (uLevel > 0) { + struct srv_info_struct *servers=NULL; + int i,count; + pstring comment; + uint32 servertype= lp_default_server_announce(); + + push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE); + + if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { + for (i=0;i 1) { + return False; /* not yet implemented */ + } + + *rdata_len = PTR_DIFF(p2,*rdata); + + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,*rdata_len); + + return True; } /**************************************************************************** @@ -2529,67 +2651,67 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *p2; - int level = SVAL(p,0); - - DEBUG(4,("NetWkstaGetInfo level %d\n",level)); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + char *p2; + int level = SVAL(p,0); - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + DEBUG(4,("NetWkstaGetInfo level %d\n",level)); - /* check it's a supported varient */ - if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) - return(False); + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - *rdata_len = mdrcnt + 1024; - *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); + /* check it's a supported varient */ + if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) { + return False; + } - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ + *rdata_len = mdrcnt + 1024; + *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); - p = *rdata; - p2 = p + 22; + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + p = *rdata; + p2 = p + 22; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ - pstrcpy(p2,get_local_machine_name()); - strupper_m(p2); - p2 = skip_string(p2,1); - p += 4; + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ + pstrcpy(p2,get_local_machine_name()); + strupper_m(p2); + p2 = skip_string(p2,1); + p += 4; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - pstrcpy(p2,current_user_info.smb_name); - p2 = skip_string(p2,1); - p += 4; + SIVAL(p,0,PTR_DIFF(p2,*rdata)); + pstrcpy(p2,current_user_info.smb_name); + p2 = skip_string(p2,1); + p += 4; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ - pstrcpy(p2,lp_workgroup()); - strupper_m(p2); - p2 = skip_string(p2,1); - p += 4; + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ + pstrcpy(p2,lp_workgroup()); + strupper_m(p2); + p2 = skip_string(p2,1); + p += 4; - SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */ - SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */ - p += 2; + SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */ + SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */ + p += 2; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */ - p2 = skip_string(p2,1); - p += 4; + SIVAL(p,0,PTR_DIFF(p2,*rdata)); + pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */ + p2 = skip_string(p2,1); + p += 4; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ - pstrcpy(p2,""); - p2 = skip_string(p2,1); - p += 4; + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ + pstrcpy(p2,""); + p2 = skip_string(p2,1); + p += 4; - *rdata_len = PTR_DIFF(p2,*rdata); + *rdata_len = PTR_DIFF(p2,*rdata); - SSVAL(*rparam,4,*rdata_len); + SSVAL(*rparam,4,*rdata_len); - return(True); + return True; } /**************************************************************************** @@ -2929,75 +3051,83 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - struct pack_desc desc; - char* name; - /* With share level security vuid will always be zero. - Don't depend on vuser being non-null !!. JRA */ - user_struct *vuser = get_valid_user_struct(vuid); - if(vuser != NULL) - DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, - vuser->user.unix_name)); - - uLevel = SVAL(p,0); - name = p + 2; - - memset((char *)&desc,'\0',sizeof(desc)); - - DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported varient */ - if (strcmp(str1,"OOWb54WrLh") != 0) return False; - if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False; - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.subformat = NULL; - desc.format = str2; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + struct pack_desc desc; + char* name; + /* With share level security vuid will always be zero. + Don't depend on vuser being non-null !!. JRA */ + user_struct *vuser = get_valid_user_struct(vuid); + + if(vuser != NULL) { + DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, + vuser->user.unix_name)); + } + + uLevel = SVAL(p,0); + name = p + 2; + + memset((char *)&desc,'\0',sizeof(desc)); + + DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name)); + + /* check it's a supported varient */ + if (strcmp(str1,"OOWb54WrLh") != 0) { + return False; + } + if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) { + return False; + } + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + + desc.base = *rdata; + desc.buflen = mdrcnt; + desc.subformat = NULL; + desc.format = str2; - if (init_package(&desc,1,0)) - { - PACKI(&desc,"W",0); /* code */ - PACKS(&desc,"B21",name); /* eff. name */ - PACKS(&desc,"B",""); /* pad */ - PACKI(&desc,"W", - conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - PACKI(&desc,"D",0); /* auth flags XXX */ - PACKI(&desc,"W",0); /* num logons */ - PACKI(&desc,"W",0); /* bad pw count */ - PACKI(&desc,"D",0); /* last logon */ - PACKI(&desc,"D",-1); /* last logoff */ - PACKI(&desc,"D",-1); /* logoff time */ - PACKI(&desc,"D",-1); /* kickoff time */ - PACKI(&desc,"D",0); /* password age */ - PACKI(&desc,"D",0); /* password can change */ - PACKI(&desc,"D",-1); /* password must change */ - { - fstring mypath; - fstrcpy(mypath,"\\\\"); - fstrcat(mypath,get_local_machine_name()); - strupper_m(mypath); - PACKS(&desc,"z",mypath); /* computer */ - } - PACKS(&desc,"z",lp_workgroup());/* domain */ - - PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ - - PACKI(&desc,"D",0x00000000); /* reserved */ - } - - *rdata_len = desc.usedlen; - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode)); - return(True); + if (init_package(&desc,1,0)) { + PACKI(&desc,"W",0); /* code */ + PACKS(&desc,"B21",name); /* eff. name */ + PACKS(&desc,"B",""); /* pad */ + PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); + PACKI(&desc,"D",0); /* auth flags XXX */ + PACKI(&desc,"W",0); /* num logons */ + PACKI(&desc,"W",0); /* bad pw count */ + PACKI(&desc,"D",0); /* last logon */ + PACKI(&desc,"D",-1); /* last logoff */ + PACKI(&desc,"D",-1); /* logoff time */ + PACKI(&desc,"D",-1); /* kickoff time */ + PACKI(&desc,"D",0); /* password age */ + PACKI(&desc,"D",0); /* password can change */ + PACKI(&desc,"D",-1); /* password must change */ + + { + fstring mypath; + fstrcpy(mypath,"\\\\"); + fstrcat(mypath,get_local_machine_name()); + strupper_m(mypath); + PACKS(&desc,"z",mypath); /* computer */ + } + + PACKS(&desc,"z",lp_workgroup());/* domain */ + PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ + PACKI(&desc,"D",0x00000000); /* reserved */ + } + + *rdata_len = desc.usedlen; + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,desc.neededlen); + + DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode)); + + return True; } /**************************************************************************** @@ -3009,24 +3139,28 @@ static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *p char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *user = skip_string(str2,1); - char *resource = skip_string(user,1); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *user = skip_string(str2,1); + char *resource = skip_string(user,1); - DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource)); + DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource)); - /* check it's a supported varient */ - if (strcmp(str1,"zzh") != 0) return False; - if (strcmp(str2,"") != 0) return False; + /* check it's a supported varient */ + if (strcmp(str1,"zzh") != 0) { + return False; + } + if (strcmp(str2,"") != 0) { + return False; + } - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,0); /* errorcode */ - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,0x7f); /* permission flags */ + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,0); /* errorcode */ + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,0x7f); /* permission flags */ - return(True); + return True; } /**************************************************************************** @@ -3038,192 +3172,224 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int count; - int i; - int snum; - fstring sharename; - uint32 jobid; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - char *tmpdata=NULL; - - uLevel = SVAL(p,2); - - memset((char *)&desc,'\0',sizeof(desc)); - memset((char *)&status,'\0',sizeof(status)); - - DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0))); - - /* check it's a supported varient */ - if (strcmp(str1,"WWrLh") != 0) return False; - if (!check_printjob_info(&desc,uLevel,str2)) return False; - - if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) - return False; - - snum = lp_servicenumber( sharename); - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = print_queue_status(snum,&queue,&status); - for (i = 0; i < count; i++) { - if (queue[i].job == jobid) break; - } - - if (mdrcnt > 0) { - *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - } else { - /* - * Don't return data but need to get correct length - * init_package will return wrong size if buflen=0 - */ - desc.buflen = getlen(desc.format); - desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); - } - - if (init_package(&desc,1,0)) { - if (i < count) { - fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); - *rdata_len = desc.usedlen; - } - else { - desc.errcode = NERR_JobNotFound; - *rdata_len = 0; - } - } - - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - SAFE_FREE(queue); - SAFE_FREE(tmpdata); - - DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); - return(True); -} + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + int count; + int i; + int snum; + fstring sharename; + uint32 jobid; + struct pack_desc desc; + print_queue_struct *queue=NULL; + print_status_struct status; + char *tmpdata=NULL; -static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* name = p; - int uLevel; - int count; - int i, succnt=0; - int snum; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - memset((char *)&desc,'\0',sizeof(desc)); - memset((char *)&status,'\0',sizeof(status)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported variant */ - if (strcmp(str1,"zWrLeh") != 0) - return False; - - if (uLevel > 2) - return False; /* defined only for uLevel 0,1,2 */ - - if (!check_printjob_info(&desc,uLevel,str2)) - return False; - - snum = find_service(name); - if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) - return False; - - count = print_queue_status(snum,&queue,&status); - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,count,0)) { - succnt = 0; - for (i = 0; i < count; i++) { - fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); - if (desc.errcode == NERR_Success) succnt = i+1; - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,count); - - SAFE_FREE(queue); - - DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); - return(True); -} + uLevel = SVAL(p,2); + + memset((char *)&desc,'\0',sizeof(desc)); + memset((char *)&status,'\0',sizeof(status)); + + DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0))); + + /* check it's a supported varient */ + if (strcmp(str1,"WWrLh") != 0) { + return False; + } + if (!check_printjob_info(&desc,uLevel,str2)) { + return False; + } + + if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) { + return False; + } + + snum = lp_servicenumber( sharename); + if (snum < 0 || !VALID_SNUM(snum)) { + return(False); + } + + count = print_queue_status(snum,&queue,&status); + for (i = 0; i < count; i++) { + if (queue[i].job == jobid) { + break; + } + } + + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + desc.base = *rdata; + desc.buflen = mdrcnt; + } else { + /* + * Don't return data but need to get correct length + * init_package will return wrong size if buflen=0 + */ + desc.buflen = getlen(desc.format); + desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); + } + + if (init_package(&desc,1,0)) { + if (i < count) { + fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); + *rdata_len = desc.usedlen; + } else { + desc.errcode = NERR_JobNotFound; + *rdata_len = 0; + } + } + + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,desc.neededlen); + + SAFE_FREE(queue); + SAFE_FREE(tmpdata); + + DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); + + return True; +} + +static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) +{ + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + char* name = p; + int uLevel; + int count; + int i, succnt=0; + int snum; + struct pack_desc desc; + print_queue_struct *queue=NULL; + print_status_struct status; + + memset((char *)&desc,'\0',sizeof(desc)); + memset((char *)&status,'\0',sizeof(status)); + + p = skip_string(p,1); + uLevel = SVAL(p,0); + + DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); + + /* check it's a supported variant */ + if (strcmp(str1,"zWrLeh") != 0) { + return False; + } + + if (uLevel > 2) { + return False; /* defined only for uLevel 0,1,2 */ + } + + if (!check_printjob_info(&desc,uLevel,str2)) { + return False; + } + + snum = find_service(name); + if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) { + return False; + } + + count = print_queue_status(snum,&queue,&status); + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + desc.base = *rdata; + desc.buflen = mdrcnt; + + if (init_package(&desc,count,0)) { + succnt = 0; + for (i = 0; i < count; i++) { + fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); + if (desc.errcode == NERR_Success) { + succnt = i+1; + } + } + } + + *rdata_len = desc.usedlen; + + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,succnt); + SSVAL(*rparam,6,count); + + SAFE_FREE(queue); + + DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); + + return True; +} static int check_printdest_info(struct pack_desc* desc, int uLevel, char* id) { - desc->subformat = NULL; - switch( uLevel ) { - case 0: desc->format = "B9"; break; - case 1: desc->format = "B9B21WWzW"; break; - case 2: desc->format = "z"; break; - case 3: desc->format = "zzzWWzzzWW"; break; - default: return False; - } - if (strcmp(desc->format,id) != 0) return False; - return True; + desc->subformat = NULL; + switch( uLevel ) { + case 0: + desc->format = "B9"; + break; + case 1: + desc->format = "B9B21WWzW"; + break; + case 2: + desc->format = "z"; + break; + case 3: + desc->format = "zzzWWzzzWW"; + break; + default: + return False; + } + if (strcmp(desc->format,id) != 0) { + return False; + } + return True; } static void fill_printdest_info(connection_struct *conn, int snum, int uLevel, struct pack_desc* desc) { - char buf[100]; - strncpy(buf,SERVICE(snum),sizeof(buf)-1); - buf[sizeof(buf)-1] = 0; - strupper_m(buf); - if (uLevel <= 1) { - PACKS(desc,"B9",buf); /* szName */ - if (uLevel == 1) { - PACKS(desc,"B21",""); /* szUserName */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"W",0); /* time */ - } - } - if (uLevel == 2 || uLevel == 3) { - PACKS(desc,"z",buf); /* pszPrinterName */ - if (uLevel == 3) { - PACKS(desc,"z",""); /* pszUserName */ - PACKS(desc,"z",""); /* pszLogAddr */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKS(desc,"z",""); /* pszComment */ - PACKS(desc,"z","NULL"); /* pszDrivers */ - PACKI(desc,"W",0); /* time */ - PACKI(desc,"W",0); /* pad1 */ - } - } + char buf[100]; + + strncpy(buf,SERVICE(snum),sizeof(buf)-1); + buf[sizeof(buf)-1] = 0; + strupper_m(buf); + + if (uLevel <= 1) { + PACKS(desc,"B9",buf); /* szName */ + if (uLevel == 1) { + PACKS(desc,"B21",""); /* szUserName */ + PACKI(desc,"W",0); /* uJobId */ + PACKI(desc,"W",0); /* fsStatus */ + PACKS(desc,"z",""); /* pszStatus */ + PACKI(desc,"W",0); /* time */ + } + } + + if (uLevel == 2 || uLevel == 3) { + PACKS(desc,"z",buf); /* pszPrinterName */ + if (uLevel == 3) { + PACKS(desc,"z",""); /* pszUserName */ + PACKS(desc,"z",""); /* pszLogAddr */ + PACKI(desc,"W",0); /* uJobId */ + PACKI(desc,"W",0); /* fsStatus */ + PACKS(desc,"z",""); /* pszStatus */ + PACKS(desc,"z",""); /* pszComment */ + PACKS(desc,"z","NULL"); /* pszDrivers */ + PACKI(desc,"W",0); /* time */ + PACKI(desc,"W",0); /* pad1 */ + } + } } static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -3231,60 +3397,64 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* PrinterName = p; - int uLevel; - struct pack_desc desc; - int snum; - char *tmpdata=NULL; - - memset((char *)&desc,'\0',sizeof(desc)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName)); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - snum = find_service(PrinterName); - if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) { - *rdata_len = 0; - desc.errcode = NERR_DestNotFound; - desc.neededlen = 0; - } - else { - if (mdrcnt > 0) { - *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - } else { - /* - * Don't return data but need to get correct length - * init_package will return wrong size if buflen=0 - */ - desc.buflen = getlen(desc.format); - desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); - } - if (init_package(&desc,1,0)) { - fill_printdest_info(conn,snum,uLevel,&desc); - } - *rdata_len = desc.usedlen; - } - - *rparam_len = 6; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); - SAFE_FREE(tmpdata); - return(True); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + char* PrinterName = p; + int uLevel; + struct pack_desc desc; + int snum; + char *tmpdata=NULL; + + memset((char *)&desc,'\0',sizeof(desc)); + + p = skip_string(p,1); + uLevel = SVAL(p,0); + + DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName)); + + /* check it's a supported varient */ + if (strcmp(str1,"zWrLh") != 0) { + return False; + } + if (!check_printdest_info(&desc,uLevel,str2)) { + return False; + } + + snum = find_service(PrinterName); + if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) { + *rdata_len = 0; + desc.errcode = NERR_DestNotFound; + desc.neededlen = 0; + } else { + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + desc.base = *rdata; + desc.buflen = mdrcnt; + } else { + /* + * Don't return data but need to get correct length + * init_package will return wrong size if buflen=0 + */ + desc.buflen = getlen(desc.format); + desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); + } + if (init_package(&desc,1,0)) { + fill_printdest_info(conn,snum,uLevel,&desc); + } + *rdata_len = desc.usedlen; + } + + *rparam_len = 6; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,desc.neededlen); + + DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); + SAFE_FREE(tmpdata); + + return True; } static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -3292,56 +3462,68 @@ static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int queuecnt; - int i, n, succnt=0; - struct pack_desc desc; - int services = lp_numservices(); - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - queuecnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) - queuecnt++; - - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,queuecnt,0)) { - succnt = 0; - n = 0; - for (i = 0; i < services; i++) { - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - fill_printdest_info(conn,i,uLevel,&desc); - n++; - if (desc.errcode == NERR_Success) succnt = n; - } - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,queuecnt); - - DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode)); - return(True); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + int queuecnt; + int i, n, succnt=0; + struct pack_desc desc; + int services = lp_numservices(); + + memset((char *)&desc,'\0',sizeof(desc)); + + uLevel = SVAL(p,0); + + DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel)); + + /* check it's a supported varient */ + if (strcmp(str1,"WrLeh") != 0) { + return False; + } + if (!check_printdest_info(&desc,uLevel,str2)) { + return False; + } + + queuecnt = 0; + for (i = 0; i < services; i++) { + if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { + queuecnt++; + } + } + + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + + desc.base = *rdata; + desc.buflen = mdrcnt; + if (init_package(&desc,queuecnt,0)) { + succnt = 0; + n = 0; + for (i = 0; i < services; i++) { + if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { + fill_printdest_info(conn,i,uLevel,&desc); + n++; + if (desc.errcode == NERR_Success) { + succnt = n; + } + } + } + } + + *rdata_len = desc.usedlen; + + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,succnt); + SSVAL(*rparam,6,queuecnt); + + DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode)); + + return True; } static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -3349,43 +3531,50 @@ static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *para char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + int succnt; + struct pack_desc desc; - memset((char *)&desc,'\0',sizeof(desc)); + memset((char *)&desc,'\0',sizeof(desc)); - uLevel = SVAL(p,0); + uLevel = SVAL(p,0); - DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel)); + DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel)); - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B41") != 0) return False; + /* check it's a supported varient */ + if (strcmp(str1,"WrLeh") != 0) { + return False; + } + if (uLevel != 0 || strcmp(str2,"B41") != 0) { + return False; + } + + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + desc.base = *rdata; + desc.buflen = mdrcnt; + if (init_package(&desc,1,0)) { + PACKS(&desc,"B41","NULL"); + } - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B41","NULL"); - } + succnt = (desc.errcode == NERR_Success ? 1 : 0); - succnt = (desc.errcode == NERR_Success ? 1 : 0); + *rdata_len = desc.usedlen; - *rdata_len = desc.usedlen; + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,succnt); + SSVAL(*rparam,6,1); - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); + DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode)); - DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode)); - return(True); + return True; } static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -3393,44 +3582,51 @@ static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + int succnt; + struct pack_desc desc; - memset((char *)&desc,'\0',sizeof(desc)); + memset((char *)&desc,'\0',sizeof(desc)); - uLevel = SVAL(p,0); + uLevel = SVAL(p,0); - DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel)); + DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel)); - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B13") != 0) return False; + /* check it's a supported varient */ + if (strcmp(str1,"WrLeh") != 0) { + return False; + } + if (uLevel != 0 || strcmp(str2,"B13") != 0) { + return False; + } - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lpd"); - } + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + desc.base = *rdata; + desc.buflen = mdrcnt; + desc.format = str2; + if (init_package(&desc,1,0)) { + PACKS(&desc,"B13","lpd"); + } + + succnt = (desc.errcode == NERR_Success ? 1 : 0); - succnt = (desc.errcode == NERR_Success ? 1 : 0); + *rdata_len = desc.usedlen; - *rdata_len = desc.usedlen; + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,succnt); + SSVAL(*rparam,6,1); - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); + DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode)); - DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode)); - return(True); + return True; } static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data, @@ -3438,45 +3634,52 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + int succnt; + struct pack_desc desc; + + memset((char *)&desc,'\0',sizeof(desc)); - memset((char *)&desc,'\0',sizeof(desc)); + uLevel = SVAL(p,0); - uLevel = SVAL(p,0); + DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel)); - DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel)); + /* check it's a supported varient */ + if (strcmp(str1,"WrLeh") != 0) { + return False; + } + if (uLevel != 0 || strcmp(str2,"B9") != 0) { + return False; + } - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B9") != 0) return False; + if (mdrcnt > 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + memset((char *)&desc,'\0',sizeof(desc)); + desc.base = *rdata; + desc.buflen = mdrcnt; + desc.format = str2; + if (init_package(&desc,1,0)) { + PACKS(&desc,"B13","lp0"); + } - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - memset((char *)&desc,'\0',sizeof(desc)); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lp0"); - } + succnt = (desc.errcode == NERR_Success ? 1 : 0); - succnt = (desc.errcode == NERR_Success ? 1 : 0); + *rdata_len = desc.usedlen; - *rdata_len = desc.usedlen; + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,succnt); + SSVAL(*rparam,6,1); - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); + DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode)); - DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode)); - return(True); + return True; } @@ -3489,59 +3692,66 @@ static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - struct pack_desc desc; - struct sessionid *session_list; - int i, num_sessions; - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel)); - DEBUG(7,("RNetSessionEnum req string=%s\n",str1)); - DEBUG(7,("RNetSessionEnum ret string=%s\n",str2)); - - /* check it's a supported varient */ - if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False; - if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False; - - num_sessions = list_sessions(&session_list); - - if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); - memset((char *)&desc,'\0',sizeof(desc)); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (!init_package(&desc,num_sessions,0)) { - return False; - } - - for(i=0; i 0) { + *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt); + } + memset((char *)&desc,'\0',sizeof(desc)); + desc.base = *rdata; + desc.buflen = mdrcnt; + desc.format = str2; + if (!init_package(&desc,num_sessions,0)) { + return False; + } + + for(i=0; i 0;i++) { + /* Ensure all the usershares are loaded. */ + become_root(); + sharecount = load_usershare_shares(); + unbecome_root(); + + for(i=0;i < sharecount && (jn_max - jn_count) > 0;i++) { if(lp_msdfs_root(i)) { jn_count += form_junctions(ctx, i,jucn,jn_max - jn_count); } diff --git a/source/smbd/ntquotas.c b/source/smbd/ntquotas.c index 9bc444d2536..a824978ecea 100644 --- a/source/smbd/ntquotas.c +++ b/source/smbd/ntquotas.c @@ -87,7 +87,7 @@ int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, id.uid = -1; - if (psid && !NT_STATUS_IS_OK(sid_to_uid(psid, &id.uid))) { + if (psid && !sid_to_uid(psid, &id.uid)) { DEBUG(0,("sid_to_uid: failed, SID[%s]\n", sid_string_static(psid))); } @@ -131,7 +131,7 @@ int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, D.isoftlimit = limit_blk2inodes(D.softlimit); D.ihardlimit = limit_blk2inodes(D.hardlimit); - if (psid && !NT_STATUS_IS_OK(sid_to_uid(psid, &id.uid))) { + if (psid && !sid_to_uid(psid, &id.uid)) { DEBUG(0,("sid_to_uid: failed, SID[%s]\n", sid_string_static(psid))); } @@ -185,10 +185,7 @@ int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list) continue; } - if (!NT_STATUS_IS_OK(uid_to_sid(&sid, usr->pw_uid))) { - DEBUG(0,("uid_to_sid failed for %ld\n",(long)usr->pw_uid)); - continue; - } + uid_to_sid(&sid, usr->pw_uid); if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &tmp_qt)!=0) { DEBUG(5,("no quota entry for sid[%s] path[%s]\n", diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index e12a24968b0..417e3421cb2 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -2309,7 +2309,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou sid_parse(pdata+4,sid_len,&sid); DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid))); - if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) { + if (!sid_to_uid(&sid, &uid)) { DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", sid_string_static(&sid),(unsigned long)sid_len)); uid = (-1); diff --git a/source/smbd/open.c b/source/smbd/open.c index 4b13e28f8e1..4f28e291cd6 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -22,6 +22,7 @@ #include "includes.h" +extern struct generic_mapping file_generic_mapping; extern struct current_user current_user; extern userdom_struct current_user_info; extern uint16 global_smbpid; @@ -1018,15 +1019,6 @@ BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func } -/* Map generic permissions to file object specific permissions */ - -struct generic_mapping file_generic_mapping = { - FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_GENERIC_ALL -}; - /**************************************************************************** Open a file with a share mode. ****************************************************************************/ diff --git a/source/smbd/password.c b/source/smbd/password.c index 764fbe8a2e9..e6445504009 100644 --- a/source/smbd/password.c +++ b/source/smbd/password.c @@ -100,7 +100,7 @@ void invalidate_vuid(uint16 vuid) session_yield(vuser); SAFE_FREE(vuser->session_keystr); - free_server_info(&vuser->server_info); + talloc_free(vuser->server_info); data_blob_free(&vuser->session_key); @@ -111,7 +111,7 @@ void invalidate_vuid(uint16 vuid) conn_clear_vuid_cache(vuid); SAFE_FREE(vuser->groups); - delete_nt_token(&vuser->nt_user_token); + talloc_free(vuser->nt_user_token); SAFE_FREE(vuser); num_validated_vuids--; } @@ -136,9 +136,11 @@ void invalidate_all_vuids(void) * @param server_info The token returned from the authentication process. * (now 'owned' by register_vuid) * - * @param session_key The User session key for the login session (now also 'owned' by register_vuid) + * @param session_key The User session key for the login session (now also + * 'owned' by register_vuid) * - * @param respose_blob The NT challenge-response, if available. (May be freed after this call) + * @param respose_blob The NT challenge-response, if available. (May be + * freed after this call) * * @param smb_name The untranslated name of the user * @@ -147,7 +149,9 @@ void invalidate_all_vuids(void) * */ -int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) +int register_vuid(auth_serversupplied_info *server_info, + DATA_BLOB session_key, DATA_BLOB response_blob, + const char *smb_name) { user_struct *vuser = NULL; @@ -179,7 +183,8 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, next_vuid = VUID_OFFSET; } - DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); + DEBUG(10,("register_vuid: allocated vuid = %u\n", + (unsigned int)next_vuid )); vuser->vuid = next_vuid; @@ -203,11 +208,14 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, vuser->n_groups = server_info->n_groups; if (vuser->n_groups) { - if (!(vuser->groups = (gid_t *)memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { - DEBUG(0,("register_vuid: failed to memdup vuser->groups\n")); + if (!(vuser->groups = (gid_t *)memdup(server_info->groups, + sizeof(gid_t) * + vuser->n_groups))) { + DEBUG(0,("register_vuid: failed to memdup " + "vuser->groups\n")); data_blob_free(&session_key); free(vuser); - free_server_info(&server_info); + talloc_free(server_info); return UID_FIELD_INVALID; } } @@ -216,26 +224,35 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, fstrcpy(vuser->user.unix_name, server_info->unix_name); /* This is a potentially untrusted username */ - alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); + alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", + sizeof(vuser->user.smb_name)); fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); - fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); + fstrcpy(vuser->user.full_name, + pdb_get_fullname(server_info->sam_account)); { /* Keep the homedir handy */ - const char *homedir = pdb_get_homedir(server_info->sam_account); - const char *logon_script = pdb_get_logon_script(server_info->sam_account); - - if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { - const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); + const char *homedir = + pdb_get_homedir(server_info->sam_account); + const char *logon_script = + pdb_get_logon_script(server_info->sam_account); + + if (!IS_SAM_DEFAULT(server_info->sam_account, + PDB_UNIXHOMEDIR)) { + const char *unix_homedir = + pdb_get_unix_homedir(server_info->sam_account); if (unix_homedir) { - vuser->unix_homedir = smb_xstrdup(unix_homedir); + vuser->unix_homedir = + smb_xstrdup(unix_homedir); } } else { - struct passwd *passwd = getpwnam_alloc(vuser->user.unix_name); + struct passwd *passwd = + getpwnam_alloc(NULL, vuser->user.unix_name); if (passwd) { - vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); - passwd_free(&passwd); + vuser->unix_homedir = + smb_xstrdup(passwd->pw_dir); + talloc_free(passwd); } } @@ -252,15 +269,18 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)vuser->uid, (unsigned int)vuser->gid, - vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest )); + vuser->user.unix_name, vuser->user.smb_name, + vuser->user.domain, vuser->guest )); - DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name)); + DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name, + vuser->user.full_name)); if (server_info->ptok) { - vuser->nt_user_token = dup_nt_token(server_info->ptok); + vuser->nt_user_token = dup_nt_token(NULL, server_info->ptok); } else { - DEBUG(1, ("server_info does not contain a user_token - cannot continue\n")); - free_server_info(&server_info); + DEBUG(1, ("server_info does not contain a user_token - " + "cannot continue\n")); + talloc_free(server_info); data_blob_free(&session_key); SAFE_FREE(vuser->homedir); SAFE_FREE(vuser->unix_homedir); @@ -273,7 +293,8 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, /* use this to keep tabs on all our info from the authentication */ vuser->server_info = server_info; - DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid)); + DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n", + (int)vuser->uid,vuser->user.unix_name, vuser->vuid)); next_vuid++; num_validated_vuids++; @@ -281,7 +302,8 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DLIST_ADD(validated_users, vuser); if (!session_claim(vuser)) { - DEBUG(1,("Failed to claim session for vuid=%d\n", vuser->vuid)); + DEBUG(1, ("Failed to claim session for vuid=%d\n", + vuser->vuid)); invalidate_vuid(vuser->vuid); return -1; } @@ -301,19 +323,26 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, int servicenumber = lp_servicenumber(vuser->user.unix_name); if ( servicenumber == -1 ) { - DEBUG(3, ("Adding homes service for user '%s' using home directory: '%s'\n", + DEBUG(3, ("Adding homes service for user '%s' using " + "home directory: '%s'\n", vuser->user.unix_name, vuser->unix_homedir)); - vuser->homes_snum = add_home_service(vuser->user.unix_name, - vuser->user.unix_name, vuser->unix_homedir); + vuser->homes_snum = + add_home_service(vuser->user.unix_name, + vuser->user.unix_name, + vuser->unix_homedir); } else { - DEBUG(3, ("Using static (or previously created) service for user '%s'; path = '%s'\n", - vuser->user.unix_name, lp_pathname(servicenumber) )); + DEBUG(3, ("Using static (or previously created) " + "service for user '%s'; path = '%s'\n", + vuser->user.unix_name, + lp_pathname(servicenumber) )); vuser->homes_snum = servicenumber; } } - if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { - /* Try and turn on server signing on the first non-guest sessionsetup. */ + if (srv_is_signing_negotiated() && !vuser->guest && + !srv_signing_started()) { + /* Try and turn on server signing on the first non-guest + * sessionsetup. */ srv_set_signing(vuser->session_key, response_blob); } @@ -344,14 +373,19 @@ void add_session_user(const char *user) if( session_userlist && in_list(suser,session_userlist,False) ) return; - if( !session_userlist || (strlen(suser) + strlen(session_userlist) + 2 >= len_session_userlist) ) { + if( !session_userlist || + (strlen(suser) + strlen(session_userlist) + 2 >= + len_session_userlist) ) { char *newlist; if (len_session_userlist > 128 * PSTRING_LEN) { - DEBUG(3,("add_session_user: session userlist already too large.\n")); + DEBUG(3,("add_session_user: session userlist already " + "too large.\n")); return; } - newlist = (char *)SMB_REALLOC( session_userlist, len_session_userlist + PSTRING_LEN ); + newlist = (char *)SMB_REALLOC( + session_userlist, + len_session_userlist + PSTRING_LEN ); if( newlist == NULL ) { DEBUG(1,("Unable to resize session_userlist\n")); return; @@ -371,7 +405,7 @@ void add_session_user(const char *user) Check if a username is valid. ****************************************************************************/ -BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) +static BOOL user_ok(const char *user, int snum) { char **valid, **invalid; BOOL ret; @@ -387,8 +421,7 @@ BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) str_list_sub_basic(invalid, current_user_info.smb_name) ) { ret = !user_in_list(user, - (const char **)invalid, - groups, n_groups); + (const char **)invalid); } } } @@ -402,8 +435,7 @@ BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) if ( valid && str_list_sub_basic(valid, current_user_info.smb_name) ) { - ret = user_in_list(user, (const char **)valid, - groups, n_groups); + ret = user_in_list(user, (const char **)valid); } } } @@ -415,8 +447,7 @@ BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { - ret = user_in_list(user, (const char **)user_list, - groups, n_groups); + ret = user_in_list(user, (const char **)user_list); } if (user_list) str_list_free (&user_list); } @@ -436,7 +467,7 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) setnetgrent(group); while (getnetgrent(&host, &user, &domain)) { if (user) { - if (user_ok(user, snum, NULL, 0) && + if (user_ok(user, snum) && password_ok(user,password)) { endnetgrent(); return(user); @@ -472,12 +503,15 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) member = member_list; for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) { - size_t member_len = strlen(gptr->gr_mem[i]) + 1; - if( copied_len + member_len < sizeof(pstring)) { + size_t member_len = strlen(gptr->gr_mem[i])+1; + if(copied_len+member_len < sizeof(pstring)) { - DEBUG(10,("validate_group: = gr_mem = %s\n", gptr->gr_mem[i])); + DEBUG(10,("validate_group: = gr_mem = " + "%s\n", gptr->gr_mem[i])); - safe_strcpy(member, gptr->gr_mem[i], sizeof(pstring) - copied_len - 1); + safe_strcpy(member, gptr->gr_mem[i], + sizeof(pstring) - + copied_len - 1); copied_len += member_len; member += copied_len; } else { @@ -491,13 +525,14 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) while (*member) { static fstring name; fstrcpy(name,member); - if (user_ok(name,snum, NULL, 0) && + if (user_ok(name,snum) && password_ok(name,password)) { endgrent(); return(&name[0]); } - DEBUG(10,("validate_group = member = %s\n", member)); + DEBUG(10,("validate_group = member = %s\n", + member)); member += strlen(member) + 1; } @@ -558,7 +593,7 @@ BOOL authorise_login(int snum, fstring user, DATA_BLOB password, auser = strtok(NULL,LIST_SEP)) { fstring user2; fstrcpy(user2,auser); - if (!user_ok(user2,snum, NULL, 0)) + if (!user_ok(user2,snum)) continue; if (password_ok(user2,password)) { @@ -595,7 +630,7 @@ BOOL authorise_login(int snum, fstring user, DATA_BLOB password, } else { fstring user2; fstrcpy(user2,auser); - if (user_ok(user2,snum, NULL, 0) && + if (user_ok(user2,snum) && password_ok(user2,password)) { ok = True; fstrcpy(user,user2); @@ -624,7 +659,7 @@ BOOL authorise_login(int snum, fstring user, DATA_BLOB password, *guest = True; } - if (ok && !user_ok(user, snum, NULL, 0)) { + if (ok && !user_ok(user, snum)) { DEBUG(0,("authorise_login: rejected invalid user %s\n",user)); ok = False; } diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 5db245ac0ce..d4dd9260897 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -925,7 +925,7 @@ static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid if (security_info_sent & OWNER_SECURITY_INFORMATION) { sid_copy(&owner_sid, psd->owner_sid); - if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) { + if (!sid_to_uid(&owner_sid, puser)) { if (lp_force_unknown_acl_user(snum)) { /* this allows take ownership to work * reasonably */ @@ -946,7 +946,7 @@ static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid if (security_info_sent & GROUP_SECURITY_INFORMATION) { sid_copy(&grp_sid, psd->grp_sid); - if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) { + if (!sid_to_gid( &grp_sid, pgrp)) { if (lp_force_unknown_acl_user(snum)) { /* this allows take group ownership to work * reasonably */ @@ -1035,7 +1035,7 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) * not uids/gids. */ - return user_in_group_list(u_name, g_name, NULL, 0); + return user_in_group(u_name, g_name); } /**************************************************************************** @@ -1390,10 +1390,10 @@ static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, if (nt4_compatible_acls()) psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; - } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid))) { + } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) { current_ace->owner_type = UID_ACE; current_ace->type = SMB_ACL_USER; - } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid))) { + } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid)) { current_ace->owner_type = GID_ACE; current_ace->type = SMB_ACL_GROUP; } else { diff --git a/source/smbd/process.c b/source/smbd/process.c index 0b7b94cce21..d646ebe02db 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -223,115 +223,6 @@ BOOL push_deferred_smb_message(uint16 mid, private_data, priv_len); } -static struct timed_event *timed_events; - -struct timed_event { - struct timed_event *next, *prev; - struct timeval when; - const char *event_name; - void (*handler)(struct timed_event *te, - const struct timeval *now, - void *private_data); - void *private_data; -}; - -static int timed_event_destructor(void *p) -{ - struct timed_event *te = talloc_get_type_abort(p, struct timed_event); - DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te, - te->event_name)); - DLIST_REMOVE(timed_events, te); - return 0; -} - -/**************************************************************************** - Schedule a function for future calling, cancel with talloc_free(). - It's the responsibility of the handler to call talloc_free() on the event - handed to it. -****************************************************************************/ - -struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, - struct timeval when, - const char *event_name, - void (*handler)(struct timed_event *te, - const struct timeval *now, - void *private_data), - void *private_data) -{ - struct timed_event *te, *last_te, *cur_te; - - te = TALLOC_P(mem_ctx, struct timed_event); - if (te == NULL) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - te->when = when; - te->event_name = event_name; - te->handler = handler; - te->private_data = private_data; - - /* keep the list ordered */ - last_te = NULL; - for (cur_te = timed_events; cur_te; cur_te = cur_te->next) { - /* if the new event comes before the current one break */ - if (!timeval_is_zero(&cur_te->when) && - timeval_compare(&te->when, &cur_te->when) < 0) { - break; - } - last_te = cur_te; - } - - DLIST_ADD_AFTER(timed_events, te, last_te); - talloc_set_destructor(te, timed_event_destructor); - - DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name, - (unsigned long)te)); - return te; -} - -static void run_events(void) -{ - struct timeval now; - - if (timed_events == NULL) { - /* No syscall if there are no events */ - DEBUG(10, ("run_events: No events\n")); - return; - } - - GetTimeOfDay(&now); - - if (timeval_compare(&now, &timed_events->when) < 0) { - /* Nothing to do yet */ - DEBUG(10, ("run_events: Nothing to do\n")); - return; - } - - DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name, - (unsigned long)timed_events)); - - timed_events->handler(timed_events, &now, timed_events->private_data); - return; -} - -struct timeval timed_events_timeout(void) -{ - struct timeval now, timeout; - - if (timed_events == NULL) { - return timeval_set(SMBD_SELECT_TIMEOUT, 0); - } - - now = timeval_current(); - timeout = timeval_until(&now, &timed_events->when); - - DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)timeout.tv_sec, - (int)timeout.tv_usec)); - - return timeout; -} - struct idle_event { struct timed_event *te; struct timeval interval; @@ -537,8 +428,10 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) } { - struct timeval tmp = timed_events_timeout(); - to = timeval_min(&to, &tmp); + struct timeval tmp; + struct timeval *tp = get_timed_events_timeout(&tmp,SMBD_SELECT_TIMEOUT); + + to = timeval_min(&to, tp); if (timeval_is_zero(&to)) { return True; } diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c index fc6a8589747..ebc47c51d9d 100644 --- a/source/smbd/sec_ctx.c +++ b/source/smbd/sec_ctx.c @@ -129,7 +129,7 @@ static void gain_root(void) Get the list of current groups. ****************************************************************************/ -int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups) +static int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups) { int i; gid_t grp; @@ -179,51 +179,6 @@ fail: return -1; } -/**************************************************************************** - Initialize the groups a user belongs to. -****************************************************************************/ - -BOOL initialise_groups(char *user, uid_t uid, gid_t gid) -{ - struct sec_ctx *prev_ctx_p; - BOOL result = True; - - if (non_root_mode()) { - return True; - } - - become_root(); - - /* Call initgroups() to get user groups */ - - if (winbind_initgroups(user,gid) == -1) { - DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) )); - if (getuid() == 0) { - if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) { - DEBUG(0,("This is probably a problem with the account %s\n", user)); - } - } - result = False; - goto done; - } - - /* Store groups in previous user's security context. This will - always work as the become_root() call increments the stack - pointer. */ - - prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1]; - - SAFE_FREE(prev_ctx_p->ut.groups); - prev_ctx_p->ut.ngroups = 0; - - get_current_groups(gid, &prev_ctx_p->ut.ngroups, &prev_ctx_p->ut.groups); - - done: - unbecome_root(); - - return result; -} - /**************************************************************************** Create a new security context on the stack. It is the same as the old one. User changes are done using the set_sec_ctx() function. @@ -252,14 +207,15 @@ BOOL push_sec_ctx(void) DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx )); - ctx_p->token = dup_nt_token(sec_ctx_stack[sec_ctx_stack_ndx-1].token); + ctx_p->token = dup_nt_token(NULL, + sec_ctx_stack[sec_ctx_stack_ndx-1].token); ctx_p->ut.ngroups = sys_getgroups(0, NULL); if (ctx_p->ut.ngroups != 0) { if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) { DEBUG(0, ("Out of memory in push_sec_ctx()\n")); - delete_nt_token(&ctx_p->token); + talloc_free(ctx_p->token); return False; } @@ -299,10 +255,10 @@ void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN if (token && (token == ctx_p->token)) smb_panic("DUPLICATE_TOKEN"); - delete_nt_token(&ctx_p->token); + talloc_free(ctx_p->token); ctx_p->ut.groups = memdup(groups, sizeof(gid_t) * ngroups); - ctx_p->token = dup_nt_token(token); + ctx_p->token = dup_nt_token(NULL, token); become_id(uid, gid); @@ -355,7 +311,7 @@ BOOL pop_sec_ctx(void) SAFE_FREE(ctx_p->ut.groups); ctx_p->ut.ngroups = 0; - delete_nt_token(&ctx_p->token); + talloc_free(ctx_p->token); /* Pop back previous user */ diff --git a/source/smbd/server.c b/source/smbd/server.c index 3e970ec16c2..6c2034988a7 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -62,6 +62,18 @@ static void smbd_set_server_fd(int fd) client_setfd(fd); } +/******************************************************************* + What to do when smb.conf is updated. + ********************************************************************/ + +static void smb_conf_updated(int msg_type, struct process_id src, + void *buf, size_t len) +{ + DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n")); + reload_services(False); +} + + /**************************************************************************** Terminate signal. ****************************************************************************/ @@ -331,6 +343,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ message_register(MSG_SMB_SAM_REPL, msg_sam_repl); message_register(MSG_SHUTDOWN, msg_exit_server); message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed); + message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); /* now accept incoming connections - forking a new process for each incoming connection */ @@ -697,6 +710,7 @@ void build_options(BOOL screen); int main(int argc,const char *argv[]) { + extern BOOL in_server; /* shall I run as a daemon */ static BOOL is_daemon = False; static BOOL interactive = False; @@ -718,6 +732,8 @@ void build_options(BOOL screen); { NULL } }; + in_server = True; + load_case_tables(); #ifdef HAVE_SET_AUTH_PARAMETERS @@ -826,11 +842,6 @@ void build_options(BOOL screen); init_structs(); - if (!init_guest_info()) { - DEBUG(0,("ERROR: failed to setup guest info.\n")); - return -1; - } - #ifdef WITH_PROFILE if (!profile_setup(False)) { DEBUG(0,("ERROR: failed to setup profiling\n")); @@ -885,9 +896,6 @@ void build_options(BOOL screen); if (!locking_init(0)) exit(1); - if (!share_info_db_init()) - exit(1); - namecache_enable(); if (!init_registry()) @@ -901,6 +909,11 @@ void build_options(BOOL screen); if (!print_backend_init()) exit(1); + if (!init_guest_info()) { + DEBUG(0,("ERROR: failed to setup guest info.\n")); + return -1; + } + /* Setup the main smbd so that we can get messages. */ /* don't worry about general printing messages here */ diff --git a/source/smbd/service.c b/source/smbd/service.c index 7640559d538..cf0116cc091 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -299,6 +299,13 @@ int find_service(fstring service) } } + /* Is it a usershare service ? */ + if (iService < 0 && *lp_usershare_path()) { + /* Ensure the name is canonicalized. */ + strlower_m(service); + iService = load_usershare_service(service); + } + if (iService >= 0) { if (!VALID_SNUM(iService)) { DEBUG(0,("Invalid snum %d for %s\n",iService, service)); @@ -359,6 +366,131 @@ static NTSTATUS share_sanity_checks(int snum, fstring dev) return NT_STATUS_OK; } +static NTSTATUS find_forced_user(int snum, BOOL vuser_is_guest, + uid_t *uid, gid_t *gid, fstring username, + struct nt_user_token **token) +{ + TALLOC_CTX *mem_ctx; + char *fuser, *found_username; + NTSTATUS result; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } + + fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S", + lp_servicename(snum)); + if (fuser == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + result = create_token_from_username(mem_ctx, fuser, vuser_is_guest, + uid, gid, &found_username, + token); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + talloc_steal(NULL, *token); + fstrcpy(username, found_username); + + result = NT_STATUS_OK; + done: + talloc_free(mem_ctx); + return result; +} + +/* + * Go through lookup_name etc to find the force'd group. + * + * Create a new token from src_token, replacing the primary group sid with the + * one found. + */ + +static NTSTATUS find_forced_group(BOOL force_user, + int snum, const char *username, + DOM_SID *pgroup_sid, + gid_t *pgid) +{ + NTSTATUS result = NT_STATUS_NO_SUCH_GROUP; + TALLOC_CTX *mem_ctx; + DOM_SID group_sid; + enum SID_NAME_USE type; + char *groupname; + BOOL user_must_be_member = False; + gid_t gid; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } + + groupname = talloc_strdup(mem_ctx, lp_force_group(snum)); + if (groupname == NULL) { + DEBUG(1, ("talloc_strdup failed\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + if (groupname[0] == '+') { + user_must_be_member = True; + groupname += 1; + } + + groupname = talloc_string_sub(mem_ctx, groupname, + "%S", lp_servicename(snum)); + + if (!lookup_name(mem_ctx, groupname, + LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, + NULL, NULL, &group_sid, &type)) { + DEBUG(10, ("lookup_name(%s) failed\n", + groupname)); + goto done; + } + + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + DEBUG(10, ("%s is a %s, not a group\n", groupname, + sid_type_lookup(type))); + goto done; + } + + if (!sid_to_gid(&group_sid, &gid)) { + DEBUG(10, ("sid_to_gid(%s) for %s failed\n", + sid_string_static(&group_sid), groupname)); + goto done; + } + + /* + * If the user has been forced and the forced group starts with a '+', + * then we only set the group to be the forced group if the forced + * user is a member of that group. Otherwise, the meaning of the '+' + * would be ignored. + */ + + if (force_user && user_must_be_member) { + if (user_in_group(username, groupname)) { + sid_copy(pgroup_sid, &group_sid); + *pgid = gid; + DEBUG(3,("Forced group %s for member %s\n", + groupname, username)); + } + } else { + sid_copy(pgroup_sid, &group_sid); + *pgid = gid; + DEBUG(3,("Forced group %s\n", groupname)); + } + + result = NT_STATUS_OK; + done: + talloc_free(mem_ctx); + return result; +} + /**************************************************************************** Make a connection, given the snum to connect to, and the vuser of the connecting user if appropriate. @@ -395,7 +527,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if (lp_guest_only(snum)) { const char *guestname = lp_guestaccount(); guest = True; - pass = getpwnam_alloc(guestname); + pass = getpwnam_alloc(NULL, guestname); if (!pass) { DEBUG(0,("make_connection_snum: Invalid guest " "account %s??\n",guestname)); @@ -408,7 +540,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->uid = pass->pw_uid; conn->gid = pass->pw_gid; string_set(&conn->user,pass->pw_name); - passwd_free(&pass); + talloc_free(pass); DEBUG(3,("Guest only user %s\n",user)); } else if (vuser) { if (vuser->guest) { @@ -421,8 +553,8 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } } else { - if (!user_ok(vuser->user.unix_name, snum, - vuser->groups, vuser->n_groups)) { + if (!user_ok_token(vuser->user.unix_name, + vuser->nt_user_token, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " "(%s)\n", vuser->user.unix_name, @@ -501,86 +633,98 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->admin_user = False; /* - * If force user is true, then store the - * given userid and also the groups - * of the user we're forcing. + * If force user is true, then store the given userid and the gid of + * the user we're forcing. + * For auxiliary groups see below. */ if (*lp_force_user(snum)) { - struct passwd *pass2; - pstring fuser; - pstrcpy(fuser,lp_force_user(snum)); - - /* Allow %S to be used by force user. */ - pstring_sub(fuser,"%S",lp_servicename(snum)); - - pass2 = (struct passwd *)Get_Pwnam(fuser); - if (pass2) { - conn->uid = pass2->pw_uid; - conn->gid = pass2->pw_gid; - string_set(&conn->user,pass2->pw_name); - fstrcpy(user,pass2->pw_name); - conn->force_user = True; - DEBUG(3,("Forced user %s\n",user)); - } else { - DEBUG(1,("Couldn't find user %s\n",fuser)); + NTSTATUS status2; + + status2 = find_forced_user(snum, + (vuser != NULL) && vuser->guest, + &conn->uid, &conn->gid, user, + &conn->nt_user_token); + if (!NT_STATUS_IS_OK(status2)) { conn_free(conn); - *status = NT_STATUS_NO_SUCH_USER; + *status = status2; return NULL; } + string_set(&conn->user,user); + conn->force_user = True; + DEBUG(3,("Forced user %s\n",user)); } -#ifdef HAVE_GETGRNAM /* * If force group is true, then override * any groupid stored for the connecting user. */ if (*lp_force_group(snum)) { - gid_t gid; - pstring gname; - pstring tmp_gname; - BOOL user_must_be_member = False; - - pstrcpy(tmp_gname,lp_force_group(snum)); - - if (tmp_gname[0] == '+') { - user_must_be_member = True; - /* even now, tmp_gname is null terminated */ - pstrcpy(gname,&tmp_gname[1]); - } else { - pstrcpy(gname,tmp_gname); - } - /* default service may be a group name */ - pstring_sub(gname,"%S",lp_servicename(snum)); - gid = nametogid(gname); - - if (gid == (gid_t)-1) { - DEBUG(1,("Couldn't find group %s\n",gname)); + NTSTATUS status2; + DOM_SID group_sid; + + status2 = find_forced_group(conn->force_user, + snum, user, + &group_sid, &conn->gid); + if (!NT_STATUS_IS_OK(status2)) { conn_free(conn); - *status = NT_STATUS_NO_SUCH_GROUP; + *status = status2; return NULL; } - /* - * If the user has been forced and the forced group starts - * with a '+', then we only set the group to be the forced - * group if the forced user is a member of that group. - * Otherwise, the meaning of the '+' would be ignored. - */ - if (conn->force_user && user_must_be_member) { - if (user_in_group_list( user, gname, NULL, 0)) { - conn->gid = gid; - DEBUG(3,("Forced group %s for member %s\n", - gname,user)); + if ((conn->nt_user_token == NULL) && (vuser != NULL)) { + + /* Not force user and not security=share, but force + * group. vuser has a token to copy */ + + conn->nt_user_token = dup_nt_token( + NULL, vuser->nt_user_token); + if (conn->nt_user_token == NULL) { + DEBUG(0, ("dup_nt_token failed\n")); + conn_free(conn); + *status = NT_STATUS_NO_MEMORY; + return NULL; } - } else { - conn->gid = gid; - DEBUG(3,("Forced group %s\n",gname)); + } + + /* If conn->nt_user_token is still NULL, we have + * security=share. This means ignore the SID, as we had no + * vuser to copy from */ + + if (conn->nt_user_token != NULL) { + /* Overwrite the primary group sid */ + sid_copy(&conn->nt_user_token->user_sids[1], + &group_sid); + } conn->force_group = True; } -#endif /* HAVE_GETGRNAM */ + + if (conn->nt_user_token != NULL) { + size_t i; + + /* We have a share-specific token from force [user|group]. + * This means we have to create the list of unix groups from + * the list of sids. */ + + conn->ngroups = 0; + conn->groups = NULL; + + for (i=0; int_user_token->num_sids; i++) { + gid_t gid; + DOM_SID *sid = &conn->nt_user_token->user_sids[i]; + + if (!sid_to_gid(sid, &gid)) { + DEBUG(10, ("Could not convert SID %s to gid, " + "ignoring it\n", + sid_string_static(sid))); + continue; + } + add_gid_to_array_unique(NULL, gid, &conn->groups, + &conn->ngroups); + } + } { pstring s; @@ -591,25 +735,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, lp_servicename(snum))); } - if (conn->force_user || conn->force_group) { - int ngroups = 0; - - /* groups stuff added by ih */ - conn->ngroups = 0; - conn->groups = NULL; - - /* Find all the groups this uid is in and - store them. Used by change_to_user() */ - initialise_groups(conn->user, conn->uid, conn->gid); - get_current_groups(conn->gid, &ngroups, &conn->groups); - conn->ngroups = ngroups; - - conn->nt_user_token = - create_nt_token(conn->uid, conn->gid, - conn->ngroups, conn->groups, - guest); - } - /* * New code to check if there's a share security descripter * added from NT server manager. This is done after the diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c index a22a575c762..38e16126e21 100644 --- a/source/smbd/sesssetup.c +++ b/source/smbd/sesssetup.c @@ -267,7 +267,7 @@ static int reply_spnego_kerberos(connection_struct *conn, map_username( user ); - pw = smb_getpwnam( user, real_username, True ); + pw = smb_getpwnam( mem_ctx, user, real_username, True ); if (!pw) { /* this was originally the behavior of Samba 2.2, if a user @@ -277,7 +277,7 @@ static int reply_spnego_kerberos(connection_struct *conn, if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ map_domainuser_to_guest = True; fstrcpy(user,lp_guestaccount()); - pw = smb_getpwnam( user, real_username, True ); + pw = smb_getpwnam( mem_ctx, user, real_username, True ); } /* extra sanity check that the guest account is valid */ @@ -302,11 +302,11 @@ static int reply_spnego_kerberos(connection_struct *conn, ret = make_server_info_pac(&server_info, real_username, pw, logon_info); if ( !NT_STATUS_IS_OK(ret) ) { - DEBUG(1,("make_server_info_pac failed!\n")); + DEBUG(1,("make_server_info_pac failed: %s!\n", + nt_errstr(ret))); SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); - passwd_free(&pw); talloc_destroy(mem_ctx); return ERROR_NT(ret); } @@ -315,26 +315,24 @@ static int reply_spnego_kerberos(connection_struct *conn, ret = make_server_info_pw(&server_info, real_username, pw); if ( !NT_STATUS_IS_OK(ret) ) { - DEBUG(1,("make_server_info_from_pw failed!\n")); + DEBUG(1,("make_server_info_pw failed: %s!\n", + nt_errstr(ret))); SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); - passwd_free(&pw); talloc_destroy(mem_ctx); return ERROR_NT(ret); } - /* make_server_info_pw does not set the domain. Without this we end up - * with the local netbios name in substitutions for %D. */ + /* make_server_info_pw does not set the domain. Without this + * we end up with the local netbios name in substitutions for + * %D. */ if (server_info->sam_account != NULL) { pdb_set_domain(server_info->sam_account, domain, PDB_SET); } } - - passwd_free(&pw); - /* register_vuid keeps the server info */ /* register_vuid takes ownership of session_key, no need to free after this. A better interface would copy it.... */ @@ -1063,6 +1061,16 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, return ERROR_NT(nt_status_squash(nt_status)); } + nt_status = create_local_token(server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("create_local_token failed: %s\n", + nt_errstr(nt_status))); + data_blob_free(&nt_resp); + data_blob_free(&lm_resp); + data_blob_clear_free(&plaintext_password); + return ERROR_NT(nt_status_squash(nt_status)); + } + if (server_info->user_session_key.data) { session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length); } else { diff --git a/source/smbd/share_access.c b/source/smbd/share_access.c new file mode 100644 index 00000000000..11e52b03ab8 --- /dev/null +++ b/source/smbd/share_access.c @@ -0,0 +1,264 @@ +/* + Unix SMB/CIFS implementation. + Check access based on valid users, read list and friends + Copyright (C) Volker Lendecke 2005 + + 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" + +/* + * No prefix means direct username + * @name means netgroup first, then unix group + * &name means netgroup + * +name means unix group + * + and & may be combined + */ + +static BOOL do_group_checks(const char **name, const char **pattern) +{ + if ((*name)[0] == '@') { + *pattern = "&+"; + *name += 1; + return True; + } + + if (((*name)[0] == '+') && ((*name)[1] == '&')) { + *pattern = "+&"; + *name += 2; + return True; + } + + if ((*name)[0] == '+') { + *pattern = "+"; + *name += 1; + return True; + } + + if (((*name)[0] == '&') && ((*name)[1] == '+')) { + *pattern = "&+"; + *name += 2; + return True; + } + + if ((*name)[0] == '&') { + *pattern = "&"; + *name += 1; + return True; + } + + return False; +} + +static BOOL token_contains_name(TALLOC_CTX *mem_ctx, + const char *username, + const char *sharename, + const struct nt_user_token *token, + const char *name) +{ + const char *prefix; + DOM_SID sid; + enum SID_NAME_USE type; + + if (username != NULL) { + name = talloc_sub_basic(mem_ctx, username, name); + } + if (sharename != NULL) { + name = talloc_string_sub(mem_ctx, name, "%S", sharename); + } + + if (name == NULL) { + /* This is too security sensitive, better panic than return a + * result that might be interpreted in a wrong way. */ + smb_panic("substitutions failed\n"); + } + + if (!do_group_checks(&name, &prefix)) { + if (!lookup_name(mem_ctx, name, LOOKUP_NAME_ALL, + NULL, NULL, &sid, &type)) { + DEBUG(5, ("lookup_name %s failed\n", name)); + return False; + } + if (type != SID_NAME_USER) { + DEBUG(5, ("%s is a %s, expected a user\n", + name, sid_type_lookup(type))); + return False; + } + return nt_token_check_sid(&sid, token); + } + + for (/* initialized above */ ; *prefix != '\0'; prefix++) { + if (*prefix == '+') { + if (!lookup_name(mem_ctx, name, + LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, + NULL, NULL, &sid, &type)) { + DEBUG(5, ("lookup_name %s failed\n", name)); + return False; + } + if ((type != SID_NAME_DOM_GRP) && + (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + DEBUG(5, ("%s is a %s, expected a group\n", + name, sid_type_lookup(type))); + return False; + } + if (nt_token_check_sid(&sid, token)) { + return True; + } + continue; + } + if (*prefix == '&') { + if (user_in_netgroup(username, name)) { + return True; + } + continue; + } + smb_panic("got invalid prefix from do_groups_check\n"); + } + return False; +} + +/* + * Check whether a user is contained in the list provided. + * + * Please note that the user name and share names passed in here mainly for + * the substitution routines that expand the parameter values, the decision + * whether a user is in the list is done after a lookup_name on the expanded + * parameter value, solely based on comparing the SIDs in token. + * + * The other use is the netgroup check when using @group or &group. + */ + +BOOL token_contains_name_in_list(const char *username, + const char *sharename, + const struct nt_user_token *token, + const char **list) +{ + TALLOC_CTX *mem_ctx; + + if (list == NULL) { + return False; + } + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + smb_panic("talloc_new failed\n"); + } + + while (*list != NULL) { + if (token_contains_name(mem_ctx, username, sharename, + token, *list)) { + talloc_free(mem_ctx); + return True; + } + list += 1; + } + + talloc_free(mem_ctx); + return False; +} + +/* + * Check whether the user described by "token" has access to share snum. + * + * This looks at "invalid users", "valid users" and "only user/username" + * + * Please note that the user name and share names passed in here mainly for + * the substitution routines that expand the parameter values, the decision + * whether a user is in the list is done after a lookup_name on the expanded + * parameter value, solely based on comparing the SIDs in token. + * + * The other use is the netgroup check when using @group or &group. + */ + +BOOL user_ok_token(const char *username, struct nt_user_token *token, int snum) +{ + if (lp_invalid_users(snum) != NULL) { + if (token_contains_name_in_list(username, lp_servicename(snum), + token, + lp_invalid_users(snum))) { + DEBUG(10, ("User %s in 'invalid users'\n", username)); + return False; + } + } + + if (lp_valid_users(snum) != NULL) { + if (!token_contains_name_in_list(username, + lp_servicename(snum), token, + lp_valid_users(snum))) { + DEBUG(10, ("User %s no in 'valid users'\n", username)); + return False; + } + } + + if (lp_onlyuser(snum)) { + const char *list[2]; + list[0] = lp_username(snum); + list[1] = NULL; + if (!token_contains_name_in_list(NULL, lp_servicename(snum), + token, list)) { + DEBUG(10, ("%s != 'username'\n", username)); + return False; + } + } + + DEBUG(10, ("user_ok_token: share %s is ok for unix user %s\n", + lp_servicename(snum), username)); + + return True; +} + +/* + * Check whether the user described by "token" is restricted to read-only + * access on share snum. + * + * This looks at "invalid users", "valid users" and "only user/username" + * + * Please note that the user name and share names passed in here mainly for + * the substitution routines that expand the parameter values, the decision + * whether a user is in the list is done after a lookup_name on the expanded + * parameter value, solely based on comparing the SIDs in token. + * + * The other use is the netgroup check when using @group or &group. + */ + +BOOL is_share_read_only_for_token(const char *username, + struct nt_user_token *token, int snum) +{ + BOOL result = lp_readonly(snum); + + if (lp_readlist(snum) != NULL) { + if (token_contains_name_in_list(username, + lp_servicename(snum), token, + lp_readlist(snum))) { + result = True; + } + } + + if (lp_writelist(snum) != NULL) { + if (token_contains_name_in_list(username, + lp_servicename(snum), token, + lp_writelist(snum))) { + result = False; + } + } + + DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user " + "%s\n", lp_servicename(snum), + result ? "read-only" : "read-write", username)); + + return result; +} diff --git a/source/smbd/uid.c b/source/smbd/uid.c index d419720c33e..6e516d35628 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -56,7 +56,7 @@ BOOL change_to_guest(void) if (!pass) { /* Don't need to free() this as its stored in a static */ - pass = getpwnam_alloc(lp_guestaccount()); + pass = getpwnam_alloc(NULL, lp_guestaccount()); if (!pass) return(False); } @@ -71,67 +71,13 @@ BOOL change_to_guest(void) current_user.conn = NULL; current_user.vuid = UID_FIELD_INVALID; - - passwd_free(&pass); + talloc_free(pass); + pass = NULL; + return True; } -/**************************************************************************** - Readonly share for this user ? -****************************************************************************/ - -static BOOL is_share_read_only_for_user(int snum, user_struct *vuser) -{ - char **list; - const char *service = lp_servicename(snum); - BOOL read_only_ret = lp_readonly(snum); - - if (!service) - return read_only_ret; - - str_list_copy(&list, lp_readlist(snum)); - if (list) { - if (!str_list_sub_basic(list, vuser->user.smb_name) ) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: read " - "list substitution failed\n")); - } - if (!str_list_substitute(list, "%S", service)) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: read " - "list service substitution failed\n")); - } - if (user_in_list(vuser->user.unix_name, (const char **)list, - vuser->groups, vuser->n_groups)) { - read_only_ret = True; - } - str_list_free(&list); - } - - str_list_copy(&list, lp_writelist(snum)); - if (list) { - if (!str_list_sub_basic(list, vuser->user.smb_name) ) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: write " - "list substitution failed\n")); - } - if (!str_list_substitute(list, "%S", service)) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: write " - "list service substitution failed\n")); - } - if (user_in_list(vuser->user.unix_name, (const char **)list, - vuser->groups, vuser->n_groups)) { - read_only_ret = False; - } - str_list_free(&list); - } - - DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user " - "%s\n", service, - read_only_ret ? "read-only" : "read-write", - vuser->user.unix_name )); - - return read_only_ret; -} - /******************************************************************* Check if a username is OK. ********************************************************************/ @@ -151,20 +97,25 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) } } - if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups)) + if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum)) return(False); - readonly_share = is_share_read_only_for_user(conn->service, vuser); + readonly_share = is_share_read_only_for_token(vuser->user.unix_name, + vuser->nt_user_token, + conn->service); if (!readonly_share && !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) { /* smb.conf allows r/w, but the security descriptor denies * write. Fall back to looking at readonly. */ readonly_share = True; - DEBUG(5,("falling back to read-only access-evaluation due to security descriptor\n")); + DEBUG(5,("falling back to read-only access-evaluation due to " + "security descriptor\n")); } - if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) { + if (!share_access_check(conn, snum, vuser, + readonly_share ? + FILE_READ_DATA : FILE_WRITE_DATA)) { return False; } @@ -176,11 +127,9 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) ent->vuid = vuser->vuid; ent->read_only = readonly_share; - if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) { - ent->admin_user = True; - } else { - ent->admin_user = False; - } + ent->admin_user = token_contains_name_in_list( + vuser->user.unix_name, NULL, vuser->nt_user_token, + lp_admin_users(conn->service)); conn->read_only = ent->read_only; conn->admin_user = ent->admin_user; @@ -217,20 +166,24 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && (current_user.ut.uid == conn->uid)) { - DEBUG(4,("change_to_user: Skipping user change - already user\n")); + DEBUG(4,("change_to_user: Skipping user change - already " + "user\n")); return(True); } else if ((current_user.conn == conn) && (vuser != 0) && (current_user.vuid == vuid) && (current_user.ut.uid == vuser->uid)) { - DEBUG(4,("change_to_user: Skipping user change - already user\n")); + DEBUG(4,("change_to_user: Skipping user change - already " + "user\n")); return(True); } snum = SNUM(conn); if ((vuser) && !check_user_ok(conn, vuser, snum)) { - DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) not permitted access to share %s.\n", - vuser->user.smb_name, vuser->user.unix_name, vuid, lp_servicename(snum))); + DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) " + "not permitted access to share %s.\n", + vuser->user.smb_name, vuser->user.unix_name, vuid, + lp_servicename(snum))); return False; } @@ -247,7 +200,8 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) current_user.ut.groups = vuser->groups; token = vuser->nt_user_token; } else { - DEBUG(2,("change_to_user: Invalid vuid used %d in accessing share %s.\n",vuid, lp_servicename(snum) )); + DEBUG(2,("change_to_user: Invalid vuid used %d in accessing " + "share %s.\n",vuid, lp_servicename(snum) )); return False; } @@ -258,7 +212,13 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) */ if((group_c = *lp_force_group(snum))) { - BOOL is_guest = False; + + token = dup_nt_token(NULL, token); + if (token == NULL) { + DEBUG(0, ("dup_nt_token failed\n")); + return False; + } + must_free_token = True; if(group_c == '+') { @@ -273,37 +233,25 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) for (i = 0; i < current_user.ut.ngroups; i++) { if (current_user.ut.groups[i] == conn->gid) { gid = conn->gid; + gid_to_sid(&token->user_sids[1], gid); break; } } } else { gid = conn->gid; + gid_to_sid(&token->user_sids[1], gid); } - - /* - * We've changed the group list in the token - we must - * re-create it. - */ - - if (vuser && vuser->guest) - is_guest = True; - - token = create_nt_token(uid, gid, current_user.ut.ngroups, current_user.ut.groups, is_guest); - if (!token) { - DEBUG(1, ("change_to_user: create_nt_token failed!\n")); - return False; - } - must_free_token = True; } - set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, token); + set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, + token); /* * Free the new token (as set_sec_ctx copies it). */ if (must_free_token) - delete_nt_token(&token); + talloc_free(token); current_user.conn = conn; current_user.vuid = vuid; @@ -344,7 +292,8 @@ BOOL become_authenticated_pipe_user(pipes_struct *p) return False; set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid, - p->pipe_user.ut.ngroups, p->pipe_user.ut.groups, p->pipe_user.nt_user_token); + p->pipe_user.ut.ngroups, p->pipe_user.ut.groups, + p->pipe_user.nt_user_token); return True; } diff --git a/source/utils/net.c b/source/utils/net.c index 25e10c6a316..069047c9ec8 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -132,6 +132,29 @@ int net_run_function(int argc, const char **argv, struct functable *table, return usage_fn(argc, argv); } +/* + * run a function from a function table. + */ +int net_run_function2(int argc, const char **argv, const char *whoami, + struct functable2 *table) +{ + int i; + + if (argc != 0) { + for (i=0; table[i].funcname; i++) { + if (StrCaseCmp(argv[0], table[i].funcname) == 0) + return table[i].fn(argc-1, argv+1); + } + } + + for (i=0; table[i].funcname != NULL; i++) { + d_printf("%s %-15s %s\n", whoami, table[i].funcname, + table[i].helptext); + } + + return -1; +} + /**************************************************************************** connect to \\server\service ****************************************************************************/ @@ -376,6 +399,8 @@ struct cli_state *net_make_ipc_connection(unsigned flags) if (NT_STATUS_IS_OK(nt_status)) { return cli; } else { + d_fprintf(stderr, "Connection failed: %s\n", + nt_errstr(nt_status)); return NULL; } } @@ -705,6 +730,7 @@ static struct functable net_func[] = { {"USER", net_user}, {"GROUP", net_group}, {"GROUPMAP", net_groupmap}, + {"SAM", net_sam}, {"VALIDATE", net_rap_validate}, {"GROUPMEMBER", net_rap_groupmember}, {"ADMIN", net_rap_admin}, @@ -722,6 +748,7 @@ static struct functable net_func[] = { {"MAXRID", net_maxrid}, {"IDMAP", net_idmap}, {"STATUS", net_status}, + {"USERSHARE", net_usershare}, {"USERSIDLIST", net_usersidlist}, #ifdef WITH_FAKE_KASERVER {"AFS", net_afs}, diff --git a/source/utils/net.h b/source/utils/net.h index 2df13cfb8f1..fc3167012d6 100644 --- a/source/utils/net.h +++ b/source/utils/net.h @@ -39,6 +39,29 @@ typedef struct copy_clistate { uint16 attribute; }copy_clistate; +struct rpc_sh_ctx { + struct cli_state *cli; + + DOM_SID *domain_sid; + char *domain_name; + + const char *whoami; + const char *thiscmd; + struct rpc_sh_cmd *cmds; + struct rpc_sh_ctx *parent; +}; + +struct rpc_sh_cmd { + const char *name; + struct rpc_sh_cmd *(*sub)(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx); + int pipe_idx; + NTSTATUS (*fn)(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv); + const char *help; +}; + /* INCLUDE FILES */ #include "utils/net_proto.h" diff --git a/source/utils/net_ads_gpo.c b/source/utils/net_ads_gpo.c new file mode 100644 index 00000000000..fec6fb88fa2 --- /dev/null +++ b/source/utils/net_ads_gpo.c @@ -0,0 +1,436 @@ +/* + Samba Unix/Linux SMB client library + net ads commands for Group Policy + Copyright (C) 2005 Guenther Deschner (gd@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" +#include "utils/net.h" + +#ifdef HAVE_ADS + +static int net_ads_gpo_usage(int argc, const char **argv) +{ + d_printf( + "net ads gpo \n"\ +" can be either:\n"\ +" ADDLINK Link a container to a GPO\n"\ +" APPLY Apply all GPOs\n"\ +" DELETELINK Delete a gPLink from a container\n"\ +" EFFECTIVE Lists all GPOs assigned to a machine\n"\ +" GETGPO Lists specified GPO\n"\ +" GETLINK Lists gPLink of a containter\n"\ +" HELP Prints this help message\n"\ +" LIST Lists all GPOs\n"\ +"\n" + ); + return -1; +} + +static int net_ads_gpo_effective(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + ADS_STRUCT *ads; + ADS_STATUS status; + const char *attrs[] = {"distinguishedName", "userAccountControl", NULL}; + void *res = NULL; + const char *filter; + char *dn = NULL; + struct GROUP_POLICY_OBJECT *gpo_list; + uint32 uac = 0; + uint32 flags = 0; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("net_ads_gpo_effective"); + if (mem_ctx == NULL) { + return -1; + } + + filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", argv[0]); + if (filter == NULL) { + goto out; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + filter, attrs, &res); + + if (!ADS_ERR_OK(status)) { + goto out; + } + + if (ads_count_replies(ads, res) != 1) { + printf("no result\n"); + goto out; + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + goto out; + } + + if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) { + goto out; + } + + if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { + flags |= GPO_LIST_FLAG_MACHINE; + } + + printf("%s: '%s' has dn: '%s'\n", + (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user", + argv[0], dn); + + status = ads_get_gpo_list(ads, mem_ctx, dn, flags, &gpo_list); + if (!ADS_ERR_OK(status)) { + goto out; + } + + printf("unsorted full dump of all GPOs for this machine:\n"); + + { + struct GROUP_POLICY_OBJECT *gpo = gpo_list; + + for (gpo = gpo_list; gpo; gpo = gpo->next) { + dump_gpo(mem_ctx, gpo); + } + } + + printf("sorted full dump of all GPOs valid for this machine:\n"); + +out: + ads_memfree(ads, dn); + ads_msgfree(ads, res); + + ads_destroy(&ads); + talloc_destroy(mem_ctx); + return 0; +} + +static int net_ads_gpo_list(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + void *res = NULL; + int num_reply = 0; + void *msg = NULL; + struct GROUP_POLICY_OBJECT gpo; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("net_ads_gpo_list"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + "(objectclass=groupPolicyContainer)", NULL, &res); + if (!ADS_ERR_OK(status)) { + d_printf("search failed: %s\n", ads_errstr(status)); + goto out; + } + + num_reply = ads_count_replies(ads, res); + + d_printf("Got %d replies\n\n", num_reply); + + /* dump the results */ + for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { + + status = ads_parse_gpo(ads, mem_ctx, msg, ads_get_dn(ads, msg), &gpo); + + if (!ADS_ERR_OK(status)) { + d_printf("parse failed: %s\n", ads_errstr(status)); + goto out; + } + + dump_gpo(mem_ctx, &gpo); + + } + +out: + ads_msgfree(ads, res); + + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_apply(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + ADS_STRUCT *ads; + ADS_STATUS status; + const char *attrs[] = {"distinguishedName", "userAccountControl", NULL}; + void *res = NULL; + const char *filter; + char *dn = NULL; + struct GROUP_POLICY_OBJECT *gpo_list; + uint32 uac = 0; + uint32 flags = 0; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("net_ads_gpo_apply"); + if (mem_ctx == NULL) { + goto out; + } + + filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", argv[0]); + if (filter == NULL) { + goto out; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + filter, attrs, &res); + + if (!ADS_ERR_OK(status)) { + goto out; + } + + if (ads_count_replies(ads, res) != 1) { + printf("no result\n"); + goto out; + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + goto out; + } + + if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) { + goto out; + } + + if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { + flags |= GPO_LIST_FLAG_MACHINE; + } + + printf("%s: '%s' has dn: '%s'\n", + (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user", + argv[0], dn); + + status = ads_get_gpo_list(ads, mem_ctx, dn, flags, &gpo_list); + if (!ADS_ERR_OK(status)) { + goto out; + } + + /* FIXME: allow to process just a single extension */ + status = gpo_process_gpo_list(ads, mem_ctx, &gpo_list, NULL, flags); + if (!ADS_ERR_OK(status)) { + goto out; + } + +out: + ads_memfree(ads, dn); + ads_msgfree(ads, res); + + ads_destroy(&ads); + talloc_destroy(mem_ctx); + return 0; +} + + +static int net_ads_gpo_get_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + struct GP_LINK gp_link; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_get_gpo_link(ads, mem_ctx, argv[0], &gp_link); + if (!ADS_ERR_OK(status)) { + d_printf("get link for %s failed: %s\n", argv[0], ads_errstr(status)); + goto out; + } + + dump_gplink(ads, mem_ctx, &gp_link); + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_add_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + uint32 gpo_opt = 0; + TALLOC_CTX *mem_ctx; + + if (argc < 2) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (argc == 3) { + gpo_opt = atoi(argv[2]); + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_add_gpo_link(ads, mem_ctx, argv[0], argv[1], gpo_opt); + if (!ADS_ERR_OK(status)) { + d_printf("add link failed: %s\n", ads_errstr(status)); + goto out; + } + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_delete_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + + if (argc < 2) { + return -1; + } + + mem_ctx = talloc_init("delete_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_delete_gpo_link(ads, mem_ctx, argv[0], argv[1]); + if (!ADS_ERR_OK(status)) { + d_printf("delete link failed: %s\n", ads_errstr(status)); + goto out; + } + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_get_gpo(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + struct GROUP_POLICY_OBJECT gpo; + uint32 sysvol_gpt_version; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_get_gpo"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + if (strnequal(argv[0], "CN={", strlen("CN={"))) { + status = ads_get_gpo(ads, mem_ctx, argv[0], NULL, NULL, &gpo); + } else { + status = ads_get_gpo(ads, mem_ctx, NULL, argv[0], NULL, &gpo); + } + + if (!ADS_ERR_OK(status)) { + d_printf("get gpo for [%s] failed: %s\n", argv[0], ads_errstr(status)); + goto out; + } + + dump_gpo(mem_ctx, &gpo); + + status = ADS_ERROR_NT(ads_gpo_get_sysvol_gpt_version(ads, mem_ctx, gpo.file_sys_path, &sysvol_gpt_version)); + if (!ADS_ERR_OK(status)) { + goto out; + } + + printf("sysvol GPT version: %d\n", sysvol_gpt_version); + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +int net_ads_gpo(int argc, const char **argv) +{ + struct functable func[] = { + {"LIST", net_ads_gpo_list}, + {"EFFECTIVE", net_ads_gpo_effective}, + {"ADDLINK", net_ads_gpo_add_link}, + {"DELETELINK", net_ads_gpo_delete_link}, + {"GETLINK", net_ads_gpo_get_link}, + {"GETGPO", net_ads_gpo_get_gpo}, + {"HELP", net_ads_gpo_usage}, + {"APPLY", net_ads_gpo_apply}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_gpo_usage); +} + +#endif diff --git a/source/utils/net_groupmap.c b/source/utils/net_groupmap.c index 1cff120c393..96a6aa531aa 100644 --- a/source/utils/net_groupmap.c +++ b/source/utils/net_groupmap.c @@ -93,6 +93,7 @@ static void print_map_entry ( GROUP_MAP map, BOOL long_list ) else { d_printf("%s\n", map.nt_name); d_printf("\tSID : %s\n", sid_string_static(&map.sid)); + d_printf("\tUnix gid : %d\n", map.gid); d_printf("\tUnix group: %s\n", gidtoname(map.gid)); d_printf("\tGroup type: %s\n", sid_type_lookup(map.sid_name_use)); @@ -261,10 +262,26 @@ static int net_groupmap_add(int argc, const char **argv) d_fprintf(stderr, "Can't lookup UNIX group %s\n", unixgrp); return -1; } + + { + GROUP_MAP map; + if (pdb_getgrgid(&map, gid)) { + d_printf("Unix group %s already mapped to SID %s\n", + unixgrp, sid_string_static(&map.sid)); + return -1; + } + } if ( (rid == 0) && (string_sid[0] == '\0') ) { - d_printf("No rid or sid specified, choosing algorithmic mapping\n"); - rid = pdb_gid_to_group_rid(gid); + d_printf("No rid or sid specified, choosing a RID\n"); + if (pdb_rid_algorithm()) { + rid = pdb_gid_to_group_rid(gid); + } else { + if (!pdb_new_rid(&rid)) { + d_printf("Could not get new RID\n"); + } + } + d_printf("Got RID %d\n", rid); } /* append the rid to our own domain/machine SID if we don't have a full SID */ @@ -423,7 +440,7 @@ static int net_groupmap_modify(int argc, const char **argv) map.gid = gid; } - if ( !pdb_update_group_mapping_entry(&map) ) { + if ( !NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map)) ) { d_fprintf(stderr, "Could not update group database\n"); return -1; } @@ -548,7 +565,7 @@ static int net_groupmap_set(int argc, const char **argv) fstrcpy(map.nt_name, ntgroup); fstrcpy(map.comment, ""); - if (!pdb_add_group_mapping_entry(&map)) { + if (!NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map))) { d_fprintf(stderr, "Could not add mapping entry for %s\n", ntgroup); return -1; @@ -582,7 +599,7 @@ static int net_groupmap_set(int argc, const char **argv) if (grp != NULL) map.gid = grp->gr_gid; - if (!pdb_update_group_mapping_entry(&map)) { + if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map))) { d_fprintf(stderr, "Could not update group mapping for %s\n", ntgroup); return -1; } @@ -633,7 +650,7 @@ static int net_groupmap_addmem(int argc, const char **argv) return -1; } - if (!pdb_add_aliasmem(&alias, &member)) { + if (!NT_STATUS_IS_OK(pdb_add_aliasmem(&alias, &member))) { d_fprintf(stderr, "Could not add sid %s to alias %s\n", argv[1], argv[0]); return -1; @@ -653,7 +670,7 @@ static int net_groupmap_delmem(int argc, const char **argv) return -1; } - if (!pdb_del_aliasmem(&alias, &member)) { + if (!NT_STATUS_IS_OK(pdb_del_aliasmem(&alias, &member))) { d_fprintf(stderr, "Could not delete sid %s from alias %s\n", argv[1], argv[0]); return -1; @@ -677,7 +694,7 @@ static int net_groupmap_listmem(int argc, const char **argv) members = NULL; num = 0; - if (!pdb_enum_aliasmem(&alias, &members, &num)) { + if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(&alias, &members, &num))) { d_fprintf(stderr, "Could not list members for sid %s\n", argv[0]); return -1; } @@ -701,8 +718,9 @@ static BOOL print_alias_memberships(TALLOC_CTX *mem_ctx, alias_rids = NULL; num_alias_rids = 0; - if (!pdb_enum_alias_memberships(mem_ctx, domain_sid, member, 1, - &alias_rids, &num_alias_rids)) { + if (!NT_STATUS_IS_OK(pdb_enum_alias_memberships( + mem_ctx, domain_sid, member, 1, + &alias_rids, &num_alias_rids))) { d_fprintf(stderr, "Could not list memberships for sid %s\n", sid_string_static(member)); return False; diff --git a/source/utils/net_help.c b/source/utils/net_help.c index c5188c3608e..79062345ab6 100644 --- a/source/utils/net_help.c +++ b/source/utils/net_help.c @@ -61,7 +61,7 @@ static int help_usage(int argc, const char **argv) "Valid functions are:\n"\ " RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\ " GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP GETLOCALSID SETLOCALSID\n"\ -" CHANGESCRETPW IDMAP\n"); +" CHANGESCRETPW LOOKUP SAM\n"); return -1; } @@ -223,8 +223,9 @@ static int net_usage(int argc, const char **argv) " net lookup\t\tto lookup host name or ip address\n"\ " net user\t\tto manage users\n"\ " net group\t\tto manage groups\n"\ + " net sam\t\tto edit the local user database directly\n"\ + " net lookup\t\tto look up various things\n"\ " net groupmap\t\tto manage group mappings\n"\ - " net idmap\t\tto manage the idmap id mappings\n"\ " net join\t\tto join a domain\n"\ " net cache\t\tto operate on cache tdb file\n"\ " net getlocalsid [NAME]\tto get the SID for local name\n"\ @@ -233,6 +234,7 @@ static int net_usage(int argc, const char **argv) " \tthis requires the -f flag as a safety barrier\n"\ " net status\t\tShow server status\n"\ " net usersidlist\tto get a list of all users with their SIDs\n" + " net usershare\t\tto add, delete and list locally user-modifiable shares\n" "\n"\ " net ads \tto run ADS commands\n"\ " net rap \tto run RAP (pre-RPC) commands\n"\ @@ -270,11 +272,12 @@ int net_help(int argc, const char **argv) {"PASSWORD", net_rap_password_usage}, {"TIME", net_time_usage}, {"LOOKUP", net_lookup_usage}, + {"USERSHARE", net_usershare_usage}, {"USERSIDLIST", net_usersidlist_usage}, #ifdef WITH_FAKE_KASERVER {"AFS", net_help_afs}, #endif - {"IDMAP", net_help_idmap}, + {"HELP", help_usage}, {NULL, NULL}}; diff --git a/source/utils/net_lookup.c b/source/utils/net_lookup.c index 8ee63515d45..dd2d666d5a0 100644 --- a/source/utils/net_lookup.c +++ b/source/utils/net_lookup.c @@ -28,6 +28,8 @@ int net_lookup_usage(int argc, const char **argv) " net lookup kdc [realm]\n\tgives IP of realm's kerberos KDC\n\n" " net lookup dc [domain]\n\tgives IP of domains Domain Controllers\n\n" " net lookup master [domain|wg]\n\tgive IP of master browser\n\n" +" net lookup name [name]\n\tLookup name's sid and type\n\n" +" net lookup sid [sid]\n\tGive sid's name and type\n\n" ); return -1; } @@ -227,6 +229,54 @@ static int net_lookup_kdc(int argc, const char **argv) return -1; } +static int net_lookup_name(int argc, const char **argv) +{ + const char *dom, *name; + DOM_SID sid; + enum SID_NAME_USE type; + + if (argc != 1) { + d_printf("usage: net lookup name \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ALL, + &dom, &name, &sid, &type)) { + d_printf("Could not lookup name %s\n", argv[0]); + return -1; + } + + d_printf("%s %d (%s) %s\\%s\n", sid_string_static(&sid), + type, sid_type_lookup(type), dom, name); + return 0; +} + +static int net_lookup_sid(int argc, const char **argv) +{ + const char *dom, *name; + DOM_SID sid; + enum SID_NAME_USE type; + + if (argc != 1) { + d_printf("usage: net lookup sid \n"); + return -1; + } + + if (!string_to_sid(&sid, argv[0])) { + d_printf("Could not convert %s to SID\n", argv[0]); + return -1; + } + + if (!lookup_sid(tmp_talloc_ctx(), &sid, + &dom, &name, &type)) { + d_printf("Could not lookup name %s\n", argv[0]); + return -1; + } + + d_printf("%s %d (%s) %s\\%s\n", sid_string_static(&sid), + type, sid_type_lookup(type), dom, name); + return 0; +} /* lookup hosts or IP addresses using internal samba lookup fns */ int net_lookup(int argc, const char **argv) @@ -239,6 +289,8 @@ int net_lookup(int argc, const char **argv) {"DC", net_lookup_dc}, {"MASTER", net_lookup_master}, {"KDC", net_lookup_kdc}, + {"NAME", net_lookup_name}, + {"SID", net_lookup_sid}, {NULL, NULL} }; diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c index 0495a7b92c2..a9dc3a1fc65 100644 --- a/source/utils/net_rpc.c +++ b/source/utils/net_rpc.c @@ -49,46 +49,42 @@ static int net_mode_share; * @return The Domain SID of the remote machine. **/ -static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx, char **domain_name) +NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx, + DOM_SID **domain_sid, char **domain_name) { struct rpc_pipe_client *lsa_pipe; - DOM_SID *domain_sid; POLICY_HND pol; NTSTATUS result = NT_STATUS_OK; uint32 info_class = 5; lsa_pipe = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &result); if (!lsa_pipe) { - fprintf(stderr, "could not initialise lsa pipe\n"); - goto error; + d_fprintf(stderr, "Could not initialise lsa pipe\n"); + return result; } result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, False, SEC_RIGHTS_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(result)) { - goto error; + d_fprintf(stderr, "open_policy failed: %s\n", + nt_errstr(result)); + return result; } - result = rpccli_lsa_query_info_policy(lsa_pipe, mem_ctx, &pol, info_class, - domain_name, &domain_sid); + result = rpccli_lsa_query_info_policy(lsa_pipe, mem_ctx, &pol, + info_class, domain_name, + domain_sid); if (!NT_STATUS_IS_OK(result)) { - error: - fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); - - if (!NT_STATUS_IS_OK(result)) { - fprintf(stderr, "error: %s\n", nt_errstr(result)); - } - - exit(1); + d_fprintf(stderr, "lsaquery failed: %s\n", + nt_errstr(result)); + return result; } - if (lsa_pipe) { - rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); - cli_rpc_pipe_close(lsa_pipe); - } + rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); + cli_rpc_pipe_close(lsa_pipe); - return domain_sid; + return NT_STATUS_OK; } /** @@ -136,7 +132,12 @@ int run_rpc_command(struct cli_state *cli_arg, return -1; } - domain_sid = net_get_remote_domain_sid(cli, mem_ctx, &domain_name); + nt_status = net_get_remote_domain_sid(cli, mem_ctx, &domain_sid, + &domain_name); + if (!NT_STATUS_IS_OK(nt_status)) { + cli_shutdown(cli); + return -1; + } if (!(conn_flags & NET_FLAGS_NO_PIPE)) { if (lp_client_schannel() && (pipe_idx == PI_NETLOGON)) { @@ -410,7 +411,7 @@ int net_rpc_join(int argc, const char **argv) * @return Normal NTSTATUS return. **/ -static NTSTATUS rpc_info_internals(const DOM_SID *domain_sid, +NTSTATUS rpc_info_internals(const DOM_SID *domain_sid, const char *domain_name, struct cli_state *cli, struct rpc_pipe_client *pipe_hnd, @@ -1219,6 +1220,380 @@ int net_rpc_user(int argc, const char **argv) return net_run_function(argc, argv, func, rpc_user_usage); } +static NTSTATUS rpc_sh_user_list(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_user_list_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_user_info(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_user_info_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_handle_user(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv, + NTSTATUS (*fn)( + TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv)) + +{ + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + uint32 rid; + enum SID_NAME_USE type; + + if (argc == 0) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + ZERO_STRUCT(connect_pol); + ZERO_STRUCT(domain_pol); + ZERO_STRUCT(user_pol); + + result = net_rpc_lookup_name(mem_ctx, pipe_hnd->cli, argv[0], + NULL, NULL, &sid, &type); + if (!NT_STATUS_IS_OK(result)) { + d_fprintf(stderr, "Could not lookup %s: %s\n", argv[0], + nt_errstr(result)); + goto done; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + if (!sid_peek_check_rid(ctx->domain_sid, &sid, &rid)) { + d_fprintf(stderr, "%s is not in our domain\n", argv[0]); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + result = rpccli_samr_connect(pipe_hnd, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + ctx->domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rid, &user_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = fn(mem_ctx, ctx, pipe_hnd, &user_pol, argc-1, argv+1); + + done: + if (is_valid_policy_hnd(&user_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); + } + if (is_valid_policy_hnd(&domain_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol); + } + if (is_valid_policy_hnd(&connect_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &connect_pol); + } + return result; +} + +static NTSTATUS rpc_sh_user_show_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *info; + + if (argc != 0) { + d_fprintf(stderr, "usage: %s show \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + info = ctr->info.id21; + + d_printf("user rid: %d, group rid: %d\n", info->user_rid, + info->group_rid); + + return result; +} + +static NTSTATUS rpc_sh_user_show(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_show_internals); +} + +#define FETCHSTR(name, rec) \ +do { if (strequal(ctx->thiscmd, name)) { \ + oldval = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_##rec); } \ +} while (0); + +#define SETSTR(name, rec, flag) \ +do { if (strequal(ctx->thiscmd, name)) { \ + init_unistr2(&usr->uni_##rec, argv[0], STR_TERMINATE); \ + init_uni_hdr(&usr->hdr_##rec, &usr->uni_##rec); \ + usr->fields_present |= ACCT_##flag; } \ +} while (0); + +static NTSTATUS rpc_sh_user_str_edit_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *usr; + const char *username; + const char *oldval = ""; + + if (argc > 1) { + d_fprintf(stderr, "usage: %s [new value|NULL]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + usr = ctr->info.id21; + + username = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_user_name); + + FETCHSTR("fullname", full_name); + FETCHSTR("homedir", home_dir); + FETCHSTR("homedrive", dir_drive); + FETCHSTR("logonscript", logon_script); + FETCHSTR("profilepath", profile_path); + FETCHSTR("description", acct_desc); + + if (argc == 0) { + d_printf("%s's %s: [%s]\n", username, ctx->thiscmd, oldval); + goto done; + } + + ZERO_STRUCTP(usr); + + if (strcmp(argv[0], "NULL") == 0) { + argv[0] = ""; + } + + SETSTR("fullname", full_name, FULL_NAME); + SETSTR("homedir", home_dir, HOME_DIR); + SETSTR("homedrive", dir_drive, HOME_DRIVE); + SETSTR("logonscript", logon_script, LOGON_SCRIPT); + SETSTR("profilepath", profile_path, PROFILE); + SETSTR("description", acct_desc, DESCRIPTION); + + result = rpccli_samr_set_userinfo2( + pipe_hnd, mem_ctx, user_hnd, 21, + &pipe_hnd->cli->user_session_key, ctr); + + d_printf("Set %s's %s from [%s] to [%s]\n", username, + ctx->thiscmd, oldval, argv[0]); + + done: + + return result; +} + +#define HANDLEFLG(name, rec) \ +do { if (strequal(ctx->thiscmd, name)) { \ + oldval = (oldflags & ACB_##rec) ? "yes" : "no"; \ + if (newval) { \ + newflags = oldflags | ACB_##rec; \ + } else { \ + newflags = oldflags & ~ACB_##rec; \ + } } } while (0); + +static NTSTATUS rpc_sh_user_str_edit(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_str_edit_internals); +} + +static NTSTATUS rpc_sh_user_flag_edit_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *usr; + const char *username; + const char *oldval = "unknown"; + uint32 oldflags, newflags; + BOOL newval; + + if ((argc > 1) || + ((argc == 1) && !strequal(argv[0], "yes") && + !strequal(argv[0], "no"))) { + d_fprintf(stderr, "usage: %s [yes|no]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + newval = strequal(argv[0], "yes"); + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + usr = ctr->info.id21; + + username = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_user_name); + oldflags = usr->acb_info; + newflags = usr->acb_info; + + HANDLEFLG("disabled", DISABLED); + HANDLEFLG("pwnotreq", PWNOTREQ); + HANDLEFLG("autolock", AUTOLOCK); + HANDLEFLG("pwnoexp", PWNOEXP); + + if (argc == 0) { + d_printf("%s's %s flag: %s\n", username, ctx->thiscmd, oldval); + goto done; + } + + ZERO_STRUCTP(usr); + + usr->acb_info = newflags; + usr->fields_present = ACCT_FLAGS; + + result = rpccli_samr_set_userinfo2( + pipe_hnd, mem_ctx, user_hnd, 21, + &pipe_hnd->cli->user_session_key, ctr); + + if (NT_STATUS_IS_OK(result)) { + d_printf("Set %s's %s flag from [%s] to [%s]\n", username, + ctx->thiscmd, oldval, argv[0]); + } + + done: + + return result; +} + +static NTSTATUS rpc_sh_user_flag_edit(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_flag_edit_internals); +} + +struct rpc_sh_cmd *net_rpc_user_edit_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "fullname", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's full name" }, + + { "homedir", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's home directory" }, + + { "homedrive", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's home drive" }, + + { "logonscript", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's logon script" }, + + { "profilepath", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's profile path" }, + + { "description", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's description" }, + + { "disabled", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user is disabled" }, + + { "autolock", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user locked out" }, + + { "pwnotreq", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user does not need a password" }, + + { "pwnoexp", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user's password does not expire" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +} + +struct rpc_sh_cmd *net_rpc_user_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_SAMR, rpc_sh_user_list, + "List available users" }, + + { "info", NULL, PI_SAMR, rpc_sh_user_info, + "List the domain groups a user is member of" }, + + { "show", NULL, PI_SAMR, rpc_sh_user_show, + "Show info about a user" }, + + { "edit", net_rpc_user_edit_cmds, 0, NULL, + "Show/Modify a user's fields" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + /****************************************************************************/ /** @@ -1580,7 +1955,7 @@ static NTSTATUS get_sid_from_name(struct cli_state *cli, } result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &lsa_pol, 1, - &name, &sids, &types); + &name, NULL, &sids, &types); if (NT_STATUS_IS_OK(result)) { sid_copy(sid, &sids[0]); @@ -2581,7 +2956,7 @@ static NTSTATUS rpc_share_add_internals(const DOM_SID *domain_sid, opt_comment, perms, opt_maxusers, num_users, path, password, level, NULL); - return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return werror_to_ntstatus(result); } static int rpc_share_add(int argc, const char **argv) @@ -4291,6 +4666,114 @@ int net_rpc_share(int argc, const char **argv) return net_run_function(argc, argv, func, rpc_share_usage); } +static NTSTATUS rpc_sh_share_list(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_share_list_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_share_add(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + WERROR result; + + if ((argc < 2) || (argc > 3)) { + d_fprintf(stderr, "usage: %s [comment]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_add( + pipe_hnd, mem_ctx, argv[0], STYPE_DISKTREE, + (argc == 3) ? argv[2] : "", + 0, 0, 0, argv[1], NULL, 2, NULL); + + return werror_to_ntstatus(result); +} + +static NTSTATUS rpc_sh_share_delete(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + WERROR result; + + if (argc != 1) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_del(pipe_hnd, mem_ctx, argv[0]); + return werror_to_ntstatus(result); +} + +static NTSTATUS rpc_sh_share_info(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + SRV_SHARE_INFO info; + SRV_SHARE_INFO_2 *info2 = &info.share.info2; + WERROR result; + + if (argc != 1) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_get_info( + pipe_hnd, mem_ctx, argv[0], 2, &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + d_printf("Name: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_netname)); + d_printf("Comment: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_remark)); + + d_printf("Path: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_path)); + d_printf("Password: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_passwd)); + + done: + return werror_to_ntstatus(result); +} + +struct rpc_sh_cmd *net_rpc_share_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_SRVSVC, rpc_sh_share_list, + "List available shares" }, + + { "add", NULL, PI_SRVSVC, rpc_sh_share_add, + "Add a share" }, + + { "delete", NULL, PI_SRVSVC, rpc_sh_share_delete, + "Delete a share" }, + + { "info", NULL, PI_SRVSVC, rpc_sh_share_info, + "Get information about a share" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + /****************************************************************************/ static int rpc_file_usage(int argc, const char **argv) @@ -5011,7 +5494,6 @@ static int rpc_trustdom_establish(int argc, const char **argv) TALLOC_CTX *mem_ctx; NTSTATUS nt_status; DOM_SID *domain_sid; - smb_ucs2_t *uni_domain_name; char* domain_name; char* domain_name_pol; @@ -5119,13 +5601,6 @@ static int rpc_trustdom_establish(int argc, const char **argv) return -1; } - if (push_ucs2_talloc(mem_ctx, &uni_domain_name, domain_name_pol) == (size_t)-1) { - DEBUG(0, ("Could not convert domain name %s to unicode\n", - domain_name_pol)); - cli_shutdown(cli); - return -1; - } - /* There should be actually query info level 3 (following nt serv behaviour), but I still don't know if it's _really_ necessary */ @@ -5134,10 +5609,8 @@ static int rpc_trustdom_establish(int argc, const char **argv) */ if (!secrets_store_trusted_domain_password(domain_name, - uni_domain_name, - strlen_w(uni_domain_name)+1, opt_password, - *domain_sid)) { + domain_sid)) { DEBUG(0, ("Storing password for trusted domain failed.\n")); cli_shutdown(cli); return -1; @@ -5253,7 +5726,6 @@ static NTSTATUS vampire_trusted_domain(struct rpc_pipe_client *pipe_hnd, LSA_TRUSTED_DOMAIN_INFO *info; char *cleartextpwd = NULL; DATA_BLOB data; - smb_ucs2_t *uni_dom_name; nt_status = rpccli_lsa_query_trusted_domain_info_by_sid(pipe_hnd, mem_ctx, pol, 4, &dom_sid, &info); @@ -5276,18 +5748,9 @@ static NTSTATUS vampire_trusted_domain(struct rpc_pipe_client *pipe_hnd, goto done; } - if (push_ucs2_talloc(mem_ctx, &uni_dom_name, trusted_dom_name) == (size_t)-1) { - DEBUG(0, ("Could not convert domain name %s to unicode\n", - trusted_dom_name)); - nt_status = NT_STATUS_UNSUCCESSFUL; - goto done; - } - if (!secrets_store_trusted_domain_password(trusted_dom_name, - uni_dom_name, - strlen_w(uni_dom_name)+1, cleartextpwd, - dom_sid)) { + &dom_sid)) { DEBUG(0, ("Storing password for trusted domain failed.\n")); nt_status = NT_STATUS_UNSUCCESSFUL; goto done; @@ -6163,7 +6626,6 @@ int net_rpc_help(int argc, const char **argv) return (net_run_function(argc, argv, func, rpc_user_usage)); } - /** * 'net rpc' entrypoint. * @param argc Standard main() style argc @@ -6194,6 +6656,7 @@ int net_rpc(int argc, const char **argv) {"rights", net_rpc_rights}, {"service", net_rpc_service}, {"registry", net_rpc_registry}, + {"shell", net_rpc_shell}, {"help", net_rpc_help}, {NULL, NULL} }; diff --git a/source/utils/net_rpc_rights.c b/source/utils/net_rpc_rights.c index 2c15fef5a09..2f02b409483 100644 --- a/source/utils/net_rpc_rights.c +++ b/source/utils/net_rpc_rights.c @@ -75,7 +75,8 @@ static NTSTATUS name_to_sid(struct rpc_pipe_client *pipe_hnd, if ( !NT_STATUS_IS_OK(result) ) return result; - result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &pol, 1, &name, &sids, &sid_types); + result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &pol, 1, &name, + NULL, &sids, &sid_types); if ( NT_STATUS_IS_OK(result) ) sid_copy( sid, &sids[0] ); @@ -488,7 +489,7 @@ static NTSTATUS rpc_rights_revoke_internal(const DOM_SID *domain_sid, done: if ( !NT_STATUS_IS_OK(result) ) { - d_fprintf(stderr, "Failed to revoke privileges for %s (%s)", + d_fprintf(stderr, "Failed to revoke privileges for %s (%s)\n", argv[0], nt_errstr(result)); } @@ -560,3 +561,53 @@ int net_rpc_rights(int argc, const char **argv) return net_help_rights( argc, argv ); } + +static NTSTATUS rpc_sh_rights_list(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_list_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_rights_grant(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_grant_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_rights_revoke(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_revoke_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +struct rpc_sh_cmd *net_rpc_rights_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_LSARPC, rpc_sh_rights_list, + "View available or assigned privileges" }, + + { "grant", NULL, PI_LSARPC, rpc_sh_rights_grant, + "Assign privilege[s]" }, + + { "revoke", NULL, PI_LSARPC, rpc_sh_rights_revoke, + "Revoke privilege[s]" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + diff --git a/source/utils/net_rpc_samsync.c b/source/utils/net_rpc_samsync.c index 09e62d9defa..45fdfbfad3e 100644 --- a/source/utils/net_rpc_samsync.c +++ b/source/utils/net_rpc_samsync.c @@ -559,7 +559,7 @@ static NTSTATUS fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta) sam_account_from_delta(sam_account, delta); DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n", sid_to_string(sid_string, &user_sid), pdb_get_username(sam_account))); - if (!pdb_update_sam_account(sam_account)) { + if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) { DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n", account)); pdb_free_sam(&sam_account); @@ -835,145 +835,6 @@ static NTSTATUS fetch_alias_info(uint32 rid, SAM_ALIAS_INFO *delta, static NTSTATUS fetch_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *delta, DOM_SID dom_sid) { -#if 0 /* - * commented out right now after talking to Volker. Can't - * do much with the membership but seemed a shame to waste - * somewhat working code. Needs testing because the membership - * that shows up surprises me. Also can't do much with groups - * in groups (e.g. Domain Admins being a member of Adminsitrators). - * --jerry - */ - - int i; - TALLOC_CTX *t = NULL; - char **nt_members = NULL; - char **unix_members; - DOM_SID group_sid; - GROUP_MAP map; - struct group *grp; - enum SID_NAME_USE sid_type; - - if (delta->num_members == 0) { - return NT_STATUS_OK; - } - - sid_copy(&group_sid, &dom_sid); - sid_append_rid(&group_sid, rid); - - if (sid_equal(&dom_sid, &global_sid_Builtin)) { - sid_type = SID_NAME_WKN_GRP; - if (!get_builtin_group_from_sid(&group_sid, &map, False)) { - DEBUG(0, ("Could not find builtin group %s\n", sid_string_static(&group_sid))); - return NT_STATUS_NO_SUCH_GROUP; - } - } else { - sid_type = SID_NAME_ALIAS; - if (!get_local_group_from_sid(&group_sid, &map, False)) { - DEBUG(0, ("Could not find local group %s\n", sid_string_static(&group_sid))); - return NT_STATUS_NO_SUCH_GROUP; - } - } - - if (!(grp = getgrgid(map.gid))) { - DEBUG(0, ("Could not find unix group %d\n", map.gid)); - return NT_STATUS_NO_SUCH_GROUP; - } - - d_printf("Group members of %s: ", grp->gr_name); - - if (!(t = talloc_init("fetch_group_mem_info"))) { - DEBUG(0, ("could not talloc_init\n")); - return NT_STATUS_NO_MEMORY; - } - - nt_members = TALLOC_ZERO_ARRAY(t, char *, delta->num_members); - - for (i=0; inum_members; i++) { - NTSTATUS nt_status; - SAM_ACCOUNT *member = NULL; - DOM_SID member_sid; - - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(t, &member))) { - talloc_destroy(t); - return nt_status; - } - - sid_copy(&member_sid, &delta->sids[i].sid); - - if (!pdb_getsampwsid(member, &member_sid)) { - DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n", - sid_string_static(&member_sid), grp->gr_name)); - pdb_free_sam(&member); - continue; - } - - if (pdb_get_group_rid(member) == rid) { - d_printf("%s(primary),", pdb_get_username(member)); - pdb_free_sam(&member); - continue; - } - - d_printf("%s,", pdb_get_username(member)); - nt_members[i] = talloc_strdup(t, pdb_get_username(member)); - pdb_free_sam(&member); - } - - d_printf("\n"); - - unix_members = grp->gr_mem; - - while (*unix_members) { - BOOL is_nt_member = False; - for (i=0; inum_members; i++) { - if (nt_members[i] == NULL) { - /* This was a primary group */ - continue; - } - - if (strcmp(*unix_members, nt_members[i]) == 0) { - is_nt_member = True; - break; - } - } - if (!is_nt_member) { - /* We look at a unix group member that is not - an nt group member. So, remove it. NT is - boss here. */ - smb_delete_user_group(grp->gr_name, *unix_members); - } - unix_members += 1; - } - - for (i=0; inum_members; i++) { - BOOL is_unix_member = False; - - if (nt_members[i] == NULL) { - /* This was the primary group */ - continue; - } - - unix_members = grp->gr_mem; - - while (*unix_members) { - if (strcmp(*unix_members, nt_members[i]) == 0) { - is_unix_member = True; - break; - } - unix_members += 1; - } - - if (!is_unix_member) { - /* We look at a nt group member that is not a - unix group member currently. So, add the nt - group member. */ - smb_add_user_group(grp->gr_name, nt_members[i]); - } - } - - talloc_destroy(t); - -#endif /* end of fetch_alias_mem() */ - return NT_STATUS_OK; } diff --git a/source/utils/net_rpc_shell.c b/source/utils/net_rpc_shell.c new file mode 100644 index 00000000000..f9675e430bc --- /dev/null +++ b/source/utils/net_rpc_shell.c @@ -0,0 +1,270 @@ +/* + * Unix SMB/CIFS implementation. + * Shell around net rpc subcommands + * Copyright (C) Volker Lendecke 2006 + * + * 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" +#include "utils/net.h" + +static struct rpc_sh_cmd sh_cmds[]; + +static NTSTATUS rpc_sh_info(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_info_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static struct rpc_sh_ctx *this_ctx; + +static char **completion_fn(const char *text, int start, int end) +{ + char **cmds = NULL; + int n_cmds = 0; + struct rpc_sh_cmd *c; + + if (start != 0) { + return NULL; + } + + ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(text), &cmds, &n_cmds); + + for (c = this_ctx->cmds; c->name != NULL; c++) { + BOOL match = (strncmp(text, c->name, strlen(text)) == 0); + + if (match) { + ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(c->name), + &cmds, &n_cmds); + } + } + + if (n_cmds == 2) { + SAFE_FREE(cmds[0]); + cmds[0] = cmds[1]; + n_cmds -= 1; + } + + ADD_TO_ARRAY(NULL, char *, NULL, &cmds, &n_cmds); + return cmds; +} + +static NTSTATUS net_sh_run(struct rpc_sh_ctx *ctx, struct rpc_sh_cmd *cmd, + int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + struct rpc_pipe_client *pipe_hnd; + NTSTATUS status; + + mem_ctx = talloc_new(ctx); + if (mem_ctx == NULL) { + d_fprintf(stderr, "talloc_new failed\n"); + return NT_STATUS_NO_MEMORY; + } + + pipe_hnd = cli_rpc_pipe_open_noauth(ctx->cli, cmd->pipe_idx, &status); + if (pipe_hnd == NULL) { + d_fprintf(stderr, "Could not open pipe: %s\n", + nt_errstr(status)); + return status; + } + + status = cmd->fn(mem_ctx, ctx, pipe_hnd, argc, argv); + + cli_rpc_pipe_close(pipe_hnd); + + talloc_destroy(mem_ctx); + + return status; +} + +static BOOL net_sh_process(struct rpc_sh_ctx *ctx, + int argc, const char **argv) +{ + struct rpc_sh_cmd *c; + struct rpc_sh_ctx *new_ctx; + NTSTATUS status; + + if (argc == 0) { + return True; + } + + if (ctx == this_ctx) { + + /* We've been called from the cmd line */ + if (strequal(argv[0], "..") && + (this_ctx->parent != NULL)) { + new_ctx = this_ctx->parent; + talloc_free(this_ctx); + this_ctx = new_ctx; + return True; + } + } + + if (strequal(argv[0], "help") || strequal(argv[0], "?")) { + for (c = ctx->cmds; c->name != NULL; c++) { + if (ctx != this_ctx) { + d_printf("%s ", ctx->whoami); + } + d_printf("%-15s %s\n", c->name, c->help); + } + return True; + } + + for (c = ctx->cmds; c->name != NULL; c++) { + if (strequal(c->name, argv[0])) { + break; + } + } + + if (c->name == NULL) { + /* None found */ + d_fprintf(stderr, "%s: unknown cmd\n", argv[0]); + return True; + } + + new_ctx = TALLOC_P(ctx, struct rpc_sh_ctx); + if (new_ctx == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return False; + } + new_ctx->cli = ctx->cli; + new_ctx->whoami = talloc_asprintf(new_ctx, "%s %s", + ctx->whoami, c->name); + new_ctx->thiscmd = talloc_strdup(new_ctx, c->name); + + if (c->sub != NULL) { + new_ctx->cmds = c->sub(new_ctx, ctx); + } else { + new_ctx->cmds = NULL; + } + + new_ctx->parent = ctx; + new_ctx->domain_name = ctx->domain_name; + new_ctx->domain_sid = ctx->domain_sid; + + argc -= 1; + argv += 1; + + if (c->sub != NULL) { + if (argc == 0) { + this_ctx = new_ctx; + return True; + } + return net_sh_process(new_ctx, argc, argv); + } + + status = net_sh_run(new_ctx, c, argc, argv); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "%s failed: %s\n", new_ctx->whoami, + nt_errstr(status)); + } + + return True; +} + +int net_rpc_shell(int argc, const char **argv) +{ + NTSTATUS status; + struct rpc_sh_ctx *ctx; + + if (argc != 0) { + d_fprintf(stderr, "usage: net rpc shell\n"); + return -1; + } + + ctx = TALLOC_P(NULL, struct rpc_sh_ctx); + if (ctx == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return -1; + } + + ctx->cli = net_make_ipc_connection(0); + if (ctx->cli == NULL) { + d_fprintf(stderr, "Could not open connection\n"); + return -1; + } + + ctx->cmds = sh_cmds; + ctx->whoami = "net rpc"; + ctx->parent = NULL; + + status = net_get_remote_domain_sid(ctx->cli, ctx, &ctx->domain_sid, + &ctx->domain_name); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + d_printf("Talking to domain %s (%s)\n", ctx->domain_name, + sid_string_static(ctx->domain_sid)); + + this_ctx = ctx; + + while(1) { + char *prompt; + char *line; + int ret; + + asprintf(&prompt, "%s> ", this_ctx->whoami); + + line = smb_readline(prompt, NULL, completion_fn); + SAFE_FREE(prompt); + + if (line == NULL) { + break; + } + + ret = poptParseArgvString(line, &argc, &argv); + if (ret != 0) { + d_fprintf(stderr, "cmdline invalid: %s\n", + poptStrerror(ret)); + return False; + } + + if ((line[0] != '\n') && + (!net_sh_process(this_ctx, argc, argv))) { + break; + } + } + + cli_shutdown(ctx->cli); + + talloc_free(ctx); + + return 0; +} + +static struct rpc_sh_cmd sh_cmds[] = { + + { "info", NULL, PI_SAMR, rpc_sh_info, + "Print information about the domain connected to" }, + + { "rights", net_rpc_rights_cmds, 0, NULL, + "List/Grant/Revoke user rights" }, + + { "share", net_rpc_share_cmds, 0, NULL, + "List/Add/Remove etc shares" }, + + { "user", net_rpc_user_cmds, 0, NULL, + "List/Add/Remove user info" }, + + { NULL, NULL, 0, NULL, NULL } +}; diff --git a/source/utils/net_sam.c b/source/utils/net_sam.c new file mode 100644 index 00000000000..ba3ec5c57f6 --- /dev/null +++ b/source/utils/net_sam.c @@ -0,0 +1,784 @@ +/* + * Unix SMB/CIFS implementation. + * Local SAM access routines + * Copyright (C) Volker Lendecke 2006 + * + * 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" +#include "utils/net.h" + +/* + * Set a user's data + */ + +static int net_sam_userset(int argc, const char **argv, const char *field, + BOOL (*fn)(SAM_ACCOUNT *, const char *, + enum pdb_value_state)) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set %s \n", + field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + if (!fn(sam_acct, argv[1], PDB_CHANGED)) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_printf("Updated %s for %s\\%s to %s\n", field, dom, name, argv[1]); + return 0; +} + +static int net_sam_set_fullname(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "fullname", + pdb_set_fullname); +} + +static int net_sam_set_logonscript(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "logonscript", + pdb_set_logon_script); +} + +static int net_sam_set_profilepath(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "profilepath", + pdb_set_profile_path); +} + +static int net_sam_set_homedrive(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "homedrive", + pdb_set_dir_drive); +} + +static int net_sam_set_homedir(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "homedir", + pdb_set_homedir); +} + +static int net_sam_set_workstations(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "workstations", + pdb_set_workstations); +} + +/* + * Set account flags + */ + +static int net_sam_set_userflag(int argc, const char **argv, const char *field, + uint16 flag) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + uint16 acct_flags; + + if ((argc != 2) || (!strequal(argv[1], "yes") && + !strequal(argv[1], "no"))) { + d_fprintf(stderr, "usage: net sam set %s [yes|no]\n", + field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + acct_flags = pdb_get_acct_ctrl(sam_acct); + + if (strequal(argv[1], "yes")) { + acct_flags |= flag; + } else { + acct_flags &= ~flag; + } + + pdb_set_acct_ctrl(sam_acct, acct_flags, PDB_CHANGED); + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_fprintf(stderr, "Updated flag %s for %s\\%s to %s\n", field, dom, + name, argv[1]); + return 0; +} + +static int net_sam_set_disabled(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "disabled", ACB_DISABLED); +} + +static int net_sam_set_pwnotreq(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "pwnotreq", ACB_PWNOTREQ); +} + +static int net_sam_set_autolock(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "autolock", ACB_AUTOLOCK); +} + +static int net_sam_set_pwnoexp(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "pwnoexp", ACB_PWNOEXP); +} + +/* + * Set a user's time field + */ + +static int net_sam_set_time(int argc, const char **argv, const char *field, + BOOL (*fn)(SAM_ACCOUNT *, time_t, + enum pdb_value_state)) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + time_t new_time; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set %s " + "[now|YYYY-MM-DD HH:MM]\n", field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (strequal(argv[1], "now")) { + new_time = time(NULL); + } else { + struct tm tm; + char *end; + ZERO_STRUCT(tm); + end = strptime(argv[1], "%Y-%m-%d %H:%M", &tm); + new_time = mktime(&tm); + if ((end == NULL) || (*end != '\0') || (new_time == -1)) { + d_fprintf(stderr, "Could not parse time string %s\n", + argv[1]); + return -1; + } + } + + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + if (!fn(sam_acct, new_time, PDB_CHANGED)) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_printf("Updated %s for %s\\%s to %s\n", field, dom, name, argv[1]); + return 0; +} + +static int net_sam_set_pwdmustchange(int argc, const char **argv) +{ + return net_sam_set_time(argc, argv, "pwdmustchange", + pdb_set_pass_must_change_time); +} + +static int net_sam_set_pwdcanchange(int argc, const char **argv) +{ + return net_sam_set_time(argc, argv, "pwdcanchange", + pdb_set_pass_can_change_time); +} + +/* + * Set a user's or a group's comment + */ + +static int net_sam_set_comment(int argc, const char **argv) +{ + GROUP_MAP map; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set comment " + "\n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type == SID_NAME_USER) { + return net_sam_userset(argc, argv, "comment", + pdb_set_acct_desc); + } + + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + d_fprintf(stderr, "%s is a %s, not a group\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!pdb_getgrsid(&map, sid)) { + d_fprintf(stderr, "Could not load group %s\n", argv[0]); + return -1; + } + + fstrcpy(map.comment, argv[1]); + + status = pdb_update_group_mapping_entry(&map); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating group mapping entry failed with " + "%s\n", nt_errstr(status)); + return -1; + } + + d_printf("Updated comment of group %s\\%s to %s\n", dom, name, + argv[1]); + + return 0; +} + +static int net_sam_set(int argc, const char **argv) +{ + struct functable2 func[] = { + { "homedir", net_sam_set_homedir, + "Change a user's home directory" }, + { "profilepath", net_sam_set_profilepath, + "Change a user's profile path" }, + { "comment", net_sam_set_comment, + "Change a users or groups description" }, + { "fullname", net_sam_set_fullname, + "Change a user's full name" }, + { "logonscript", net_sam_set_logonscript, + "Change a user's logon script" }, + { "homedrive", net_sam_set_homedrive, + "Change a user's home drive" }, + { "workstations", net_sam_set_workstations, + "Change a user's allowed workstations" }, + { "disabled", net_sam_set_disabled, + "Disable/Enable a user" }, + { "pwnotreq", net_sam_set_pwnotreq, + "Disable/Enable the password not required flag" }, + { "autolock", net_sam_set_autolock, + "Disable/Enable a user's lockout flag" }, + { "pwnoexp", net_sam_set_pwnoexp, + "Disable/Enable whether a user's pw does not expire" }, + { "pwdmustchange", net_sam_set_pwdmustchange, + "Set a users password must change time" }, + { "pwdcanchange", net_sam_set_pwdcanchange, + "Set a users password can change time" }, + {NULL, NULL} + }; + + return net_run_function2(argc, argv, "net sam set", func); +} + +/* + * Map a unix group to a domain group + */ + +static int net_sam_mapunixgroup(int argc, const char **argv) +{ + NTSTATUS status; + GROUP_MAP map; + struct group *grp; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam mapunixgroup \n"); + return -1; + } + + grp = getgrnam(argv[0]); + if (grp == NULL) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + status = map_unix_group(grp, &map); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Mapping group %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + d_printf("Mapped unix group %s to SID %s\n", argv[0], + sid_string_static(&map.sid)); + + return 0; +} + +/* + * Create a local group + */ + +static int net_sam_createlocalgroup(int argc, const char **argv) +{ + NTSTATUS status; + uint32 rid; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam createlocalgroup \n"); + return -1; + } + + if (!winbind_ping()) { + d_fprintf(stderr, "winbind seems not to run. createlocalgroup " + "only works when winbind runs.\n"); + return -1; + } + + status = pdb_create_alias(argv[0], &rid); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Creating %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + d_printf("Created local group %s with RID %d\n", argv[0], rid); + + return 0; +} + +/* + * Add a group member + */ + +static int net_sam_addmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname, *memberdomain, *membername; + DOM_SID group, member; + enum SID_NAME_USE grouptype, membertype; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam addmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[1], LOOKUP_NAME_ISOLATED, + &memberdomain, &membername, &member, &membertype)) { + d_fprintf(stderr, "Could not find member %s\n", argv[1]); + return -1; + } + + if ((grouptype == SID_NAME_ALIAS) || (grouptype == SID_NAME_WKN_GRP)) { + if ((membertype != SID_NAME_USER) && + (membertype != SID_NAME_DOM_GRP)) { + d_fprintf(stderr, "%s is a local group, only users " + "and domain groups can be added.\n" + "%s is a %s\n", argv[0], argv[1], + sid_type_lookup(membertype)); + return -1; + } + status = pdb_add_aliasmem(&group, &member); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Adding local group member failed " + "with %s\n", nt_errstr(status)); + return -1; + } + } else { + d_fprintf(stderr, "Can only add members to local groups so " + "far, %s is a %s\n", argv[0], + sid_type_lookup(grouptype)); + return -1; + } + + d_printf("Added %s\\%s to %s\\%s\n", + memberdomain, membername, groupdomain, groupname); + + return 0; +} + +/* + * Delete a group member + */ + +static int net_sam_delmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname; + const char *memberdomain = NULL; + const char *membername = NULL; + DOM_SID group, member; + enum SID_NAME_USE grouptype; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam delmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[1], LOOKUP_NAME_ISOLATED, + &memberdomain, &membername, &member, NULL)) { + if (!string_to_sid(&member, argv[1])) { + d_fprintf(stderr, "Could not find member %s\n", + argv[1]); + return -1; + } + } + + if ((grouptype == SID_NAME_ALIAS) || + (grouptype == SID_NAME_WKN_GRP)) { + status = pdb_del_aliasmem(&group, &member); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Deleting local group member failed " + "with %s\n", nt_errstr(status)); + return -1; + } + } else { + d_fprintf(stderr, "Can only delete members from local groups " + "so far, %s is a %s\n", argv[0], + sid_type_lookup(grouptype)); + return -1; + } + + if (membername != NULL) { + d_printf("Deleted %s\\%s from %s\\%s\n", + memberdomain, membername, groupdomain, groupname); + } else { + d_printf("Deleted %s from %s\\%s\n", + sid_string_static(&member), groupdomain, groupname); + } + + return 0; +} + +/* + * List group members + */ + +static int net_sam_listmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname; + DOM_SID group; + enum SID_NAME_USE grouptype; + NTSTATUS status; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam listmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if ((grouptype == SID_NAME_ALIAS) || + (grouptype == SID_NAME_WKN_GRP)) { + DOM_SID *members = NULL; + size_t i, num_members = 0; + + status = pdb_enum_aliasmem(&group, &members, &num_members); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Listing group members failed with " + "%s\n", nt_errstr(status)); + return -1; + } + + d_printf("%s\\%s has %d members\n", groupdomain, groupname, + num_members); + for (i=0; i 1) || + ((argc == 1) && !strequal(argv[0], "verbose"))) { + d_fprintf(stderr, "usage: net sam list %s [verbose]\n", what); + return -1; + } + + if (search == NULL) { + d_fprintf(stderr, "Could not start search\n"); + return -1; + } + + while (True) { + struct samr_displayentry entry; + if (!search->next_entry(search, &entry)) { + break; + } + if (verbose) { + d_printf("%s:%d:%s\n", + entry.account_name, + entry.rid, + entry.description); + } else { + d_printf("%s\n", entry.account_name); + } + } + + search->search_end(search); + return 0; +} + +static int net_sam_list_users(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, pdb_search_users(ACB_NORMAL), + "users"); +} + +static int net_sam_list_groups(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, pdb_search_groups(), "groups"); +} + +static int net_sam_list_localgroups(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_aliases(get_global_sam_sid()), + "localgroups"); +} + +static int net_sam_list_builtin(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_aliases(&global_sid_Builtin), + "builtin"); +} + +static int net_sam_list_workstations(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_users(ACB_WSTRUST), + "workstations"); +} + +/* + * List stuff + */ + +static int net_sam_list(int argc, const char **argv) +{ + struct functable2 func[] = { + { "users", net_sam_list_users, + "List SAM users" }, + { "groups", net_sam_list_groups, + "List SAM groups" }, + { "localgroups", net_sam_list_localgroups, + "List SAM local groups" }, + { "builtin", net_sam_list_builtin, + "List builtin groups" }, + { "workstations", net_sam_list_workstations, + "List domain member workstations" }, + {NULL, NULL} + }; + + return net_run_function2(argc, argv, "net sam list", func); +} + +/* + * Show details of SAM entries + */ + +static int net_sam_show(int argc, const char **argv) +{ + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam show \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + d_printf("%s\\%s is a %s with SID %s\n", dom, name, + sid_type_lookup(type), sid_string_static(&sid)); + + return 0; +} + +/*********************************************************** + migrated functionality from smbgroupedit + **********************************************************/ +int net_sam(int argc, const char **argv) +{ + struct functable2 func[] = { + { "createlocalgroup", net_sam_createlocalgroup, + "Create a new local group" }, + { "mapunixgroup", net_sam_mapunixgroup, + "Map a unix group to a domain group" }, + { "addmem", net_sam_addmem, + "Add a member to a group" }, + { "delmem", net_sam_delmem, + "Delete a member from a group" }, + { "listmem", net_sam_listmem, + "List group members" }, + { "list", net_sam_list, + "List users, groups and local groups" }, + { "show", net_sam_show, + "Show details of a SAM entry" }, + { "set", net_sam_set, + "Set details of a SAM account" }, + { NULL, NULL, NULL } + }; + + /* we shouldn't have silly checks like this */ + if (getuid() != 0) { + d_fprintf(stderr, "You must be root to edit the SAM " + "directly.\n"); + return -1; + } + + return net_run_function2(argc, argv, "net sam", func); +} + diff --git a/source/utils/net_usershare.c b/source/utils/net_usershare.c new file mode 100644 index 00000000000..c00f239b99a --- /dev/null +++ b/source/utils/net_usershare.c @@ -0,0 +1,829 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) Jeremy Allison (jra@samba.org) 2005 + + 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" +#include "utils/net.h" + +struct { + const char *us_errstr; + enum usershare_err us_err; +} us_errs [] = { + {"",USERSHARE_OK}, + {"Malformed usershare file", USERSHARE_MALFORMED_FILE}, + {"Bad version number", USERSHARE_BAD_VERSION}, + {"Malformed path entry", USERSHARE_MALFORMED_PATH}, + {"Malformed comment entryfile", USERSHARE_MALFORMED_COMMENT_DEF}, + {"Malformed acl definition", USERSHARE_MALFORMED_ACL_DEF}, + {"Acl parse error", USERSHARE_ACL_ERR}, + {"Path not absolute", USERSHARE_PATH_NOT_ABSOLUTE}, + {"Path is denied", USERSHARE_PATH_IS_DENIED}, + {"Path not allowed", USERSHARE_PATH_NOT_ALLOWED}, + {"Path is not a directory", USERSHARE_PATH_NOT_DIRECTORY}, + {"System error", USERSHARE_POSIX_ERR}, + {NULL,(enum usershare_err)-1} +}; + +static const char *get_us_error_code(enum usershare_err us_err) +{ + static pstring out; + int idx = 0; + + while (us_errs[idx].us_errstr != NULL) { + if (us_errs[idx].us_err == us_err) { + return us_errs[idx].us_errstr; + } + idx++; + } + + slprintf(out, sizeof(out), "Usershare error code (0x%x)", (unsigned int)us_err); + return out; +} + +/* The help subsystem for the USERSHARE subcommand */ + +static int net_usershare_add_usage(int argc, const char **argv) +{ + char c = *lp_winbind_separator(); + d_printf( + "net usershare add [-l|--long] [] []\n" + "\tAdds the specified share name for this user.\n" + "\t is the new share name.\n" + "\t is the path on the filesystem to export.\n" + "\t is the optional comment for the new share.\n" + "\t is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n" + "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n" + "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n" + "\t\tname may be a domain user or group. For local users use the local server name " + "instead of \"DOMAIN\"\n" + "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n" + "\tAdd -l or --long to print the info on the newly added share.\n", + c, c ); + return -1; +} + +static int net_usershare_delete_usage(int argc, const char **argv) +{ + d_printf( + "net usershare delete \n"\ + "\tdeletes the specified share name for this user.\n"); + return -1; +} + +static int net_usershare_info_usage(int argc, const char **argv) +{ + d_printf( + "net usershare info [-l|--long] [wildcard sharename]\n"\ + "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n" + "\tBy default only gives info on shares owned by the current user\n" + "\tAdd -l or --long to apply this to all shares\n" + "\tOmit the sharename or use a wildcard of '*' to see all shares\n"); + return -1; +} + +static int net_usershare_list_usage(int argc, const char **argv) +{ + d_printf( + "net usershare list [-l|--long] [wildcard sharename]\n"\ + "\tLists the names of all shares that match the wildcard.\n" + "\tBy default only lists shares owned by the current user\n" + "\tAdd -l or --long to apply this to all shares\n" + "\tOmit the sharename or use a wildcard of '*' to see all shares\n"); + return -1; +} + +int net_usershare_usage(int argc, const char **argv) +{ + d_printf("net usershare add [] [] to add or change a user defined share.\n" + "net usershare delete to delete a user defined share.\n" + "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n" + "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n" + "net usershare help\n"\ + "\nType \"net usershare help