diff options
author | Gerald Carter <jerry@samba.org> | 2006-02-03 22:19:41 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:06:23 -0500 |
commit | 0af1500fc0bafe61019f1b2ab1d9e1d369221240 (patch) | |
tree | 653fc2533795458d5f9696402285d9f14e527a21 | |
parent | 21a30a1346c9f9a25659a0cea0d276d8c2e6ddca (diff) | |
download | samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.tar.gz samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.tar.bz2 samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.zip |
r13316: Let the carnage begin....
Sync with trunk as off r13315
(This used to be commit 17e63ac4ed8325c0d44fe62b2442449f3298559f)
185 files changed, 22252 insertions, 7131 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 6c182a6e41..281d58f23d 100644 --- a/source3/Makefile.in +++ b/source3/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/source3/auth/auth.c b/source3/auth/auth.c index df7d6fc9c6..6dc30383d5 100644 --- a/source3/auth/auth.c +++ b/source3/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/source3/auth/auth_builtin.c b/source3/auth/auth_builtin.c index 96c2221652..d4d6d49e40 100644 --- a/source3/auth/auth_builtin.c +++ b/source3/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/source3/auth/auth_compat.c b/source3/auth/auth_compat.c index 2ac70d7354..28b9de8d43 100644 --- a/source3/auth/auth_compat.c +++ b/source3/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/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index 266851b229..81ae7c1340 100644 --- a/source3/auth/auth_domain.c +++ b/source3/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/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c index 2fef8f1e9b..2bf86860cc 100644 --- a/source3/auth/auth_ntlmssp.c +++ b/source3/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/source3/auth/auth_rhosts.c b/source3/auth/auth_rhosts.c index b561e3d42b..e310fa80fd 100644 --- a/source3/auth/auth_rhosts.c +++ b/source3/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/source3/auth/auth_sam.c b/source3/auth/auth_sam.c index 558c181f70..fb53941b79 100644 --- a/source3/auth/auth_sam.c +++ b/source3/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/source3/auth/auth_script.c b/source3/auth/auth_script.c index 1a715fca31..1bc33ec59e 100644 --- a/source3/auth/auth_script.c +++ b/source3/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/source3/auth/auth_server.c b/source3/auth/auth_server.c index 7bce32ef2b..8eed8bba6a 100644 --- a/source3/auth/auth_server.c +++ b/source3/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/source3/auth/auth_unix.c b/source3/auth/auth_unix.c index f744cba0c4..df0703d348 100644 --- a/source3/auth/auth_unix.c +++ b/source3/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/source3/auth/auth_util.c b/source3/auth/auth_util.c index eb15fff7c8..27dab9b9aa 100644 --- a/source3/auth/auth_util.c +++ b/source3/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; i<ptoken->num_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; i<num_aliases; i++) { + DOM_SID alias_sid; + sid_compose(&alias_sid, domain_sid, aliases[i]); + add_sid_to_array_unique(token, &alias_sid, + &token->user_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; i<token->num_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; i<num_groupsids; i++) { + add_sid_to_array_unique(result, &groupsids[i], + &result->user_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; i<result->num_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; i<server_info->ptok->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; i<num_group_sids; i++) { + gid_to_sid(&group_sids[i], gids[i]); + } + *found_username = talloc_strdup(mem_ctx, pass->pw_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); @@ -1506,38 +1667,19 @@ void free_user_info(auth_usersupplied_info **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 ***************************************************************************/ 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); @@ -1551,40 +1693,28 @@ BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_me } /**************************************************************************** - 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/source3/auth/auth_winbind.c b/source3/auth/auth_winbind.c index ad72bd9a1f..6e2f26a572 100644 --- a/source3/auth/auth_winbind.c +++ b/source3/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/source3/configure.in b/source3/configure.in index 7079bf7437..e901e065d2 100644 --- a/source3/configure.in +++ b/source3/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/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index 7dc0426c44..2790d47587 100644 --- a/source3/groupdb/mapping.c +++ b/source3/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/source3/include/ads.h b/source3/include/ads.h index decb823ea9..ce643666ad 100644 --- a/source3/include/ads.h +++ b/source3/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/source3/include/auth.h b/source3/include/auth.h index 03206c03c6..79fbb93895 100644 --- a/source3/include/auth.h +++ b/source3/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/source3/include/doserr.h b/source3/include/doserr.h index 62c1e4fa22..8f8ea06696 100644 --- a/source3/include/doserr.h +++ b/source3/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/source3/include/event.h b/source3/include/event.h new file mode 100644 index 0000000000..fdb990678d --- /dev/null +++ b/source3/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/source3/include/gpo.h b/source3/include/gpo.h new file mode 100644 index 0000000000..65c96c31e6 --- /dev/null +++ b/source3/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/source3/include/idmap.h b/source3/include/idmap.h index c81b94a718..474982f292 100644 --- a/source3/include/idmap.h +++ b/source3/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/source3/include/includes.h b/source3/include/includes.h index a9b792d5f6..8aa1003240 100644 --- a/source3/include/includes.h +++ b/source3/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/source3/include/local.h b/source3/include/local.h index c9b54ab1a2..916fb6e46d 100644 --- a/source3/include/local.h +++ b/source3/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/source3/include/messages.h b/source3/include/messages.h index 4b1732d42d..dc4f4ca2c0 100644 --- a/source3/include/messages.h +++ b/source3/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/source3/include/nt_status.h b/source3/include/nt_status.h index ab768258df..14c83eba4b 100644 --- a/source3/include/nt_status.h +++ b/source3/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/source3/include/passdb.h b/source3/include/passdb.h index f1896710dc..0035fc5b05 100644 --- a/source3/include/passdb.h +++ b/source3/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/source3/include/rpc_dfs.h b/source3/include/rpc_dfs.h index 7aee208c14..adf25c9938 100644 --- a/source3/include/rpc_dfs.h +++ b/source3/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/source3/include/rpc_lsa.h b/source3/include/rpc_lsa.h index dd255c28d5..c8d6a210b5 100644 --- a/source3/include/rpc_lsa.h +++ b/source3/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/source3/include/rpc_netlogon.h b/source3/include/rpc_netlogon.h index c1d8540344..91f85601e3 100644 --- a/source3/include/rpc_netlogon.h +++ b/source3/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/source3/include/rpc_samr.h b/source3/include/rpc_samr.h index 342db37ea5..2fae514c3d 100644 --- a/source3/include/rpc_samr.h +++ b/source3/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/source3/include/secrets.h b/source3/include/secrets.h index f2d1afd96b..610a14b52b 100644 --- a/source3/include/secrets.h +++ b/source3/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/source3/include/smb.h b/source3/include/smb.h index 3a6f68b9ec..b167e4ee12 100644 --- a/source3/include/smb.h +++ b/source3/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/source3/include/smbldap.h b/source3/include/smbldap.h index bea1a6d84a..8870205bbb 100644 --- a/source3/include/smbldap.h +++ b/source3/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/source3/intl/lang_tdb.c b/source3/intl/lang_tdb.c index d3422f0d78..d20a15d90e 100644 --- a/source3/intl/lang_tdb.c +++ b/source3/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/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c index 1b31dff499..9b587224e3 100644 --- a/source3/lib/dummysmbd.c +++ b/source3/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/source3/lib/events.c b/source3/lib/events.c new file mode 100644 index 0000000000..314f074979 --- /dev/null +++ b/source3/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/source3/lib/genrand.c b/source3/lib/genrand.c index f37bbc9c2f..5b643bf297 100644 --- a/source3/lib/genrand.c +++ b/source3/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/source3/lib/messages.c b/source3/lib/messages.c index 058bbc99b0..2d6518aed6 100644 --- a/source3/lib/messages.c +++ b/source3/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/source3/lib/pam_errors.c b/source3/lib/pam_errors.c index 212d3831fd..8a4c41d7df 100644 --- a/source3/lib/pam_errors.c +++ b/source3/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/source3/lib/pidfile.c b/source3/lib/pidfile.c index b041eb7f1b..08e41083b5 100644 --- a/source3/lib/pidfile.c +++ b/source3/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/source3/lib/readline.c b/source3/lib/readline.c index 78b99fd7fb..c1f1dc7f40 100644 --- a/source3/lib/readline.c +++ b/source3/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/source3/lib/secdesc.c b/source3/lib/secdesc.c index ace0aee866..273bf0f0a3 100644 --- a/source3/lib/secdesc.c +++ b/source3/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/source3/lib/sharesec.c b/source3/lib/sharesec.c new file mode 100644 index 0000000000..b98e304582 --- /dev/null +++ b/source3/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/source3/lib/smbldap.c b/source3/lib/smbldap.c index 609816b877..c045be51c5 100644 --- a/source3/lib/smbldap.c +++ b/source3/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/source3/lib/smbldap_util.c b/source3/lib/smbldap_util.c index 4679b86487..7b4cf4d079 100644 --- a/source3/lib/smbldap_util.c +++ b/source3/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/source3/lib/system_smbd.c b/source3/lib/system_smbd.c index 6c65f61ad7..1d4f88fbb9 100644 --- a/source3/lib/system_smbd.c +++ b/source3/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<count; ) { - if ( groups[i-1] == groups[i] ) { - memmove( &groups[i-1], &groups[i], (count - i + 1)*sizeof(gid_t) ); - - /* decrement the total number of groups and do not increment - the loop counter */ - count--; - continue; - } - i++; - } - - *num_groups = count; - - DEBUG(8,("remove_duplicate_gids: Exit %d gids\n", *num_groups)); - - return; -} - /* This is a *much* faster way of getting the list of groups for a user without changing the current supplementary group list. The old @@ -79,7 +38,8 @@ void remove_duplicate_gids( int *num_groups, gid_t *groups ) NOTE!! this function only works if it is called as root! */ -static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, int *grpcnt) +static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, + int *grpcnt) { gid_t *gids_saved; int ret, ngrp_saved, num_gids; @@ -140,9 +100,6 @@ static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, in } groups[0] = gid; *grpcnt = ret + 1; - - /* remove any duplicates gids in the list */ - remove_duplicate_gids( grpcnt, groups ); } restore_re_gid(); @@ -169,11 +126,11 @@ static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grp /* see if we should disable winbindd lookups for local users */ if (strchr(user, *lp_winbind_separator()) == NULL) { if ( !winbind_off() ) - DEBUG(0,("sys_getgroup_list: Insufficient environment space for %s\n", - WINBINDD_DONT_ENV)); + DEBUG(0,("sys_getgroup_list: Insufficient environment space " + "for %s\n", WINBINDD_DONT_ENV)); else - DEBUG(10,("sys_getgrouplist(): disabled winbindd for group lookup [user == %s]\n", - user)); + DEBUG(10,("sys_getgrouplist(): disabled winbindd for group " + "lookup [user == %s]\n", user)); } #ifdef HAVE_GETGROUPLIST @@ -190,8 +147,9 @@ static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grp return retval; } -static BOOL getgroups_user(const char *user, gid_t primary_gid, - gid_t **ret_groups, size_t *p_ngroups) +BOOL getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user, + gid_t primary_gid, + gid_t **ret_groups, size_t *p_ngroups) { size_t ngrp; int max_grp; @@ -229,10 +187,11 @@ static BOOL getgroups_user(const char *user, gid_t primary_gid, groups = NULL; /* Add in primary group first */ - add_gid_to_array_unique(NULL, primary_gid, &groups, &ngrp); + add_gid_to_array_unique(mem_ctx, primary_gid, &groups, &ngrp); for (i=0; i<max_grp; i++) - add_gid_to_array_unique(NULL, temp_groups[i], &groups, &ngrp); + add_gid_to_array_unique(mem_ctx, temp_groups[i], + &groups, &ngrp); *p_ngroups = ngrp; *ret_groups = groups; @@ -241,15 +200,22 @@ static BOOL getgroups_user(const char *user, gid_t primary_gid, } NTSTATUS pdb_default_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) { size_t i; + gid_t gid; + + if (!sid_to_gid(pdb_get_group_sid(user), &gid)) { + DEBUG(10, ("sid_to_gid failed\n")); + return NT_STATUS_NO_SUCH_USER; + } - if (!getgroups_user(username, primary_gid, pp_gids, p_num_groups)) { + if (!getgroups_unix_user(mem_ctx, pdb_get_username(user), gid, + pp_gids, p_num_groups)) { return NT_STATUS_NO_SUCH_USER; } @@ -257,22 +223,15 @@ NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods, smb_panic("primary group missing"); } - *pp_sids = SMB_MALLOC_ARRAY(DOM_SID, *p_num_groups); + *pp_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *p_num_groups); if (*pp_sids == NULL) { - SAFE_FREE(pp_gids); + talloc_free(*pp_gids); return NT_STATUS_NO_MEMORY; } for (i=0; i<*p_num_groups; i++) { - if (!NT_STATUS_IS_OK(gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]))) { - DEBUG(1, ("get_user_groups: failed to convert " - "gid %ld to a sid!\n", - (long int)(*pp_gids)[i+1])); - SAFE_FREE(*pp_sids); - SAFE_FREE(*pp_gids); - return NT_STATUS_NO_SUCH_USER; - } + gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]); } return NT_STATUS_OK; diff --git a/source3/lib/username.c b/source3/lib/username.c index 7d66b320ad..c04dfd05da 100644 --- a/source3/lib/username.c +++ b/source3/lib/username.c @@ -22,8 +22,12 @@ #include "includes.h" /* internal functions */ -static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (const char *), int N); -static struct passwd *uname_string_combinations2(char *s, int offset, 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); +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); /***************************************************************** Check if a user or group name is local (this is a *local* name for @@ -108,7 +112,7 @@ BOOL map_username(fstring user) } numlines = 0; - qlines = fd_lines_load(fd, &numlines); + qlines = fd_lines_load(fd, &numlines,0); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); close(fd); @@ -180,7 +184,8 @@ BOOL map_username(fstring user) return False; } - if (strchr_m(dosname,'*') || user_in_list(user, (const char **)dosuserlist, NULL, 0)) { + if (strchr_m(dosname,'*') || + user_in_list(user, (const char **)dosuserlist)) { DEBUG(3,("Mapped user %s to %s\n",user,unixname)); mapped_user = True; fstrcpy( last_from,user ); @@ -218,7 +223,8 @@ BOOL map_username(fstring user) static struct passwd *Get_Pwnam_ret = NULL; -static struct passwd *Get_Pwnam_internals(const char *user, char *user2) +static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx, + const char *user, char *user2) { struct passwd *ret = NULL; @@ -232,7 +238,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2) common case on UNIX systems */ strlower_m(user2); DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2)); - ret = getpwnam_alloc(user2); + ret = getpwnam_alloc(mem_ctx, user2); if(ret) goto done; @@ -240,7 +246,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2) if(strcmp(user, user2) != 0) { DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n", user)); - ret = getpwnam_alloc(user); + ret = getpwnam_alloc(mem_ctx, user); if(ret) goto done; } @@ -250,7 +256,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2) if(strcmp(user, user2) != 0) { DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n", user2)); - ret = getpwnam_alloc(user2); + ret = getpwnam_alloc(mem_ctx, user2); if(ret) goto done; } @@ -259,7 +265,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2) strlower_m(user2); DEBUG(5,("Checking combinations of %d uppercase letters in %s\n", lp_usernamelevel(), user2)); - ret = uname_string_combinations(user2, getpwnam_alloc, + ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc, lp_usernamelevel()); done: @@ -275,7 +281,7 @@ done: This will return an allocated structure ****************************************************************************/ -struct passwd *Get_Pwnam_alloc(const char *user) +struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user) { fstring user2; struct passwd *ret; @@ -289,7 +295,7 @@ struct passwd *Get_Pwnam_alloc(const char *user) DEBUG(5,("Finding user %s\n", user)); - ret = Get_Pwnam_internals(user, user2); + ret = Get_Pwnam_internals(mem_ctx, user, user2); return ret; } @@ -303,7 +309,7 @@ struct passwd *Get_Pwnam(const char *user) { struct passwd *ret; - ret = Get_Pwnam_alloc(user); + ret = Get_Pwnam_alloc(NULL, user); /* This call used to just return the 'passwd' static buffer. This could then have accidental reuse implications, so @@ -320,7 +326,7 @@ struct passwd *Get_Pwnam(const char *user) */ if (Get_Pwnam_ret) { - passwd_free(&Get_Pwnam_ret); + talloc_free(Get_Pwnam_ret); } Get_Pwnam_ret = ret; @@ -333,7 +339,7 @@ struct passwd *Get_Pwnam(const char *user) try lower case. ****************************************************************************/ -static BOOL user_in_netgroup_list(const char *user, const char *ngname) +BOOL user_in_netgroup(const char *user, const char *ngname) { #ifdef HAVE_NETGROUP static char *mydomain = NULL; @@ -351,7 +357,7 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) user, mydomain, ngname)); if (innetgr(ngname, NULL, user, mydomain)) { - DEBUG(5,("user_in_netgroup_list: Found\n")); + DEBUG(5,("user_in_netgroup: Found\n")); return (True); } else { @@ -367,7 +373,7 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) lowercase_user, mydomain, ngname)); if (innetgr(ngname, NULL, lowercase_user, mydomain)) { - DEBUG(5,("user_in_netgroup_list: Found\n")); + DEBUG(5,("user_in_netgroup: Found\n")); return (True); } } @@ -379,8 +385,8 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) Check if a user is in a winbind group. ****************************************************************************/ -static BOOL user_in_winbind_group_list(const char *user, const char *gname, - BOOL *winbind_answered) +static BOOL user_in_winbind_group(const char *user, const char *gname, + BOOL *winbind_answered) { int i; gid_t gid, gid_low, gid_high; @@ -392,7 +398,7 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, *winbind_answered = False; if ((gid = nametogid(gname)) == (gid_t)-1) { - DEBUG(0,("user_in_winbind_group_list: nametogid for group %s " + DEBUG(0,("user_in_winbind_group: nametogid for group %s " "failed.\n", gname )); goto err; } @@ -439,11 +445,11 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, } else - DEBUG(10,("user_in_winbind_group_list: using cached user " + DEBUG(10,("user_in_winbind_group: using cached user " "groups for [%s]\n", user)); if ( DEBUGLEVEL >= 10 ) { - DEBUG(10,("user_in_winbind_group_list: using groups -- ")); + DEBUG(10,("user_in_winbind_group: using groups -- ")); for ( i=0; i<num_groups; i++ ) DEBUGADD(10,("%lu ", (unsigned long)groups[i])); DEBUGADD(10,("\n")); @@ -477,13 +483,13 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, Check if a user is in a UNIX group. ****************************************************************************/ -BOOL user_in_unix_group_list(const char *user,const char *gname) +BOOL user_in_unix_group(const char *user,const char *gname) { struct passwd *pass = Get_Pwnam(user); struct sys_userlist *user_list; struct sys_userlist *member; - DEBUG(10,("user_in_unix_group_list: checking user %s in group %s\n", + DEBUG(10,("user_in_unix_group: checking user %s in group %s\n", user, gname)); /* @@ -493,7 +499,7 @@ BOOL user_in_unix_group_list(const char *user,const char *gname) if (pass) { if (strequal(gname,gidtoname(pass->pw_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/source3/lib/util.c b/source3/lib/util.c index 38878befc7..dc57839df3 100644 --- a/source3/lib/util.c +++ b/source3/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/source3/lib/util_file.c b/source3/lib/util_file.c index 407a8b24fc..53a9bc9b41 100644 --- a/source3/lib/util_file.c +++ b/source3/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/source3/lib/util_pw.c b/source3/lib/util_pw.c index 13349bad34..e026affb44 100644 --- a/source3/lib/util_pw.c +++ b/source3/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; i<PWNAMCACHE_SIZE; i++) - pwnam_cache[i] = NULL; + pwnam_cache = TALLOC_ZERO_ARRAY(NULL, struct passwd *, + PWNAMCACHE_SIZE); + if (pwnam_cache == NULL) { + smb_panic("Could not init pwnam_cache\n"); + } - pwnam_cache_initialized = True; return; } void flush_pwnam_cache(void) { - int i; - + talloc_free(pwnam_cache); + pwnam_cache = NULL; init_pwnam_cache(); - - for (i=0; i<PWNAMCACHE_SIZE; i++) { - if (pwnam_cache[i] == NULL) - continue; - - passwd_free(&pwnam_cache[i]); - } } -struct passwd *getpwnam_alloc(const char *name) +struct passwd *getpwnam_alloc(TALLOC_CTX *mem_ctx, const char *name) { int i; @@ -96,7 +72,7 @@ struct passwd *getpwnam_alloc(const char *name) if ((pwnam_cache[i] != NULL) && (strcmp(name, pwnam_cache[i]->pw_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/source3/lib/util_sid.c b/source3/lib/util_sid.c index e2b2ebf28c..c7f9dc2fdb 100644 --- a/source3/lib/util_sid.c +++ b/source3/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/source3/lib/util_str.c b/source3/lib/util_str.c index 0b02487f77..85b5cfc90a 100644 --- a/source3/lib/util_str.c +++ b/source3/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; i<max_len && name[i]; i++ ) { + /* fail if strchr_m() finds one of the invalid characters */ + if ( name[i] && strchr_m( invalid_chars, name[i] ) ) { + return False; + } + } + + return True; +} + diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c index 880416a549..bc90314fce 100644 --- a/source3/lib/util_unistr.c +++ b/source3/lib/util_unistr.c @@ -291,24 +291,18 @@ int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src) * have been to manually talloc_strdup them in rpc_client/cli_netlogon.c. */ -size_t rpcstr_pull_unistr2_talloc(TALLOC_CTX *mem_ctx, char **dest, - UNISTR2 *src) +char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *mem_ctx, UNISTR2 *src) { pstring tmp; size_t result; result = pull_ucs2(NULL, tmp, src->buffer, 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/source3/libads/gpo.c b/source3/libads/gpo.c new file mode 100644 index 0000000000..9cf7aae977 --- /dev/null +++ b/source3/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/source3/libads/gpo_util.c b/source3/libads/gpo_util.c new file mode 100644 index 0000000000..8f913c1971 --- /dev/null +++ b/source3/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; i<gp_ext.num_exts; i++) { + + if (extension_guid && !strequal(extension_guid, gp_ext.extensions_guid[i])) { + continue; + } + + status = process_extension_with_snapin(ads, mem_ctx, gp_ext.extensions_guid[i], + gp_ext.snapins_guid[i]); + if (!ADS_ERR_OK(status)) { + return status; + } + } + + return ADS_ERROR(LDAP_SUCCESS); +} + +ADS_STATUS gpo_process_gpo_list(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + struct GROUP_POLICY_OBJECT **gpo_list, + const char *extensions_guid, + uint32 flags) +{ + ADS_STATUS status; + struct GROUP_POLICY_OBJECT *gpo = *gpo_list; + + for (gpo = *gpo_list; gpo; gpo = gpo->next) { + + 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/source3/libads/kerberos.c b/source3/libads/kerberos.c index d5b4b11fa2..67f8433775 100644 --- a/source3/libads/kerberos.c +++ b/source3/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/source3/libads/krb5_errs.c b/source3/libads/krb5_errs.c new file mode 100644 index 0000000000..cd227d4377 --- /dev/null +++ b/source3/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/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c index 31d0a02cad..6ffd218e96 100644 --- a/source3/libads/krb5_setpw.c +++ b/source3/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/source3/libads/ldap.c b/source3/libads/ldap.c index e503da62a4..8444989bac 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Tridgell 2001 Copyright (C) Remus Koos 2001 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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 @@ -808,6 +809,65 @@ char *ads_get_dn(ADS_STRUCT *ads, void *msg) } /** + * 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 * @param res ** which will contain results - free res* with ads_msgfree() @@ -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/source3/libads/sasl.c b/source3/libads/sasl.c index f6adfb5108..d8d33a924f 100644 --- a/source3/libads/sasl.c +++ b/source3/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/source3/libmsrpc/cac_lsarpc.c b/source3/libmsrpc/cac_lsarpc.c index d2e52f01a4..b157f33c69 100644 --- a/source3/libmsrpc/cac_lsarpc.c +++ b/source3/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/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 7c15c8d19f..6f32fb1b5d 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/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/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 51f21397f7..c5cf75783b 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/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/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 2f980adcf8..55addd44a6 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/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/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index e0dcefeb1d..55a705d7f0 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/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; @@ -991,10 +994,154 @@ out: #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/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index 48780e28df..252dafcfa8 100644 --- a/source3/libsmb/clilist.c +++ b/source3/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/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index cc481a066a..13bf1a866c 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/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/source3/libsmb/conncache.c b/source3/libsmb/conncache.c index 2af4d57b80..49512d7a2e 100644 --- a/source3/libsmb/conncache.c +++ b/source3/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/source3/libsmb/errormap.c b/source3/libsmb/errormap.c index 3c0b13ad6f..f6b5af068a 100644 --- a/source3/libsmb/errormap.c +++ b/source3/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/source3/libsmb/gpo.c b/source3/libsmb/gpo.c new file mode 100644 index 0000000000..0257138ece --- /dev/null +++ b/source3/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/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c index 44cb43c285..03dbd71e93 100644 --- a/source3/libsmb/libsmbclient.c +++ b/source3/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/source3/libsmb/passchange.c b/source3/libsmb/passchange.c index 8b811b06ea..673671d28d 100644 --- a/source3/libsmb/passchange.c +++ b/source3/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/source3/nsswitch/pam_winbind.c b/source3/nsswitch/pam_winbind.c index 61c01daa16..57e05dc4bb 100644 --- a/source3/nsswitch/pam_winbind.c +++ b/source3/nsswitch/pam_winbind.c @@ -3,12 +3,14 @@ Copyright Andrew Tridgell <tridge@samba.org> 2000 Copyright Tim Potter <tpot@samba.org> 2000 Copyright Andrew Bartlett <abartlet@samba.org> 2002 + Copyright Guenther Deschner <gd@samba.org> 2005-2006 largely based on pam_userdb by Cristian Gafton <gafton@redhat.com> also contains large slabs of code from pam_unix by Elliot Lee <sopwith@redhat.com> (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; i<argc; i++ ) { + + if ((strncmp(argv[i], item, strlen(item)) == 0)) { + char *p; + + parm = SMB_STRDUP(argv[i]); + + if ( (p = strchr( parm, '=' )) == NULL) { + _pam_log(LOG_INFO, "no \"=\" delimiter for \"%s\" found\n", item); + goto out; + } + SAFE_FREE(parm); + _pam_log_debug(ctrl, LOG_INFO, "PAM config: %s '%s'\n", item, p+1); + return p + 1; + } + } + + _pam_log_debug(ctrl, LOG_INFO, "CONFIG file: %s '%s'\n", item, parm_opt); +out: + SAFE_FREE(parm); + return parm_opt; +} + +const char *get_krb5_cc_type_from_config(int argc, const char **argv, int ctrl) +{ + return get_conf_item_string(argc, argv, ctrl, "krb5_ccache_type", WINBIND_KRB5_CCACHE_TYPE); +} + +const char *get_member_from_config(int argc, const char **argv, int ctrl) +{ + const char *ret = NULL; + ret = get_conf_item_string(argc, argv, ctrl, "require_membership_of", WINBIND_REQUIRED_MEMBERSHIP); + if (ret) { + return ret; + } + return get_conf_item_string(argc, argv, ctrl, "require-membership-of", WINBIND_REQUIRED_MEMBERSHIP); +} + PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { - const char *username; - const char *password; - const char *member = NULL; - int retval = PAM_AUTH_ERR; - int i; - - /* parse arguments */ - int ctrl = _pam_parse(argc, argv); - - /* Get the username */ - retval = pam_get_user(pamh, &username, NULL); - if ((retval != PAM_SUCCESS) || (!username)) { - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_DEBUG,"can not get the username"); - return PAM_SERVICE_ERR; - } - - retval = _winbind_read_password(pamh, ctrl, NULL, - "Password: ", NULL, - &password); - - if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "Could not retrieve user's password"); - return PAM_AUTHTOK_ERR; - } - - if (ctrl & WINBIND_DEBUG_ARG) { - - /* Let's not give too much away in the log file */ + const char *username; + const char *password; + const char *member = NULL; + const char *cctype = NULL; + int retval = PAM_AUTH_ERR; + + /* 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_authenticate"); + + /* Get the username */ + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + _pam_log_debug(ctrl, LOG_DEBUG, "can not get the username"); + return PAM_SERVICE_ERR; + } + + retval = _winbind_read_password(pamh, ctrl, NULL, + "Password: ", NULL, + &password); + + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR, "Could not retrieve user's password"); + return PAM_AUTHTOK_ERR; + } + + /* Let's not give too much away in the log file */ #ifdef DEBUG_PASSWORD - _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", - username, password); + _pam_log_debug(ctrl, LOG_INFO, "Verify user `%s' with password `%s'", + username, password); #else - _pam_log(LOG_INFO, "Verify user `%s'", username); + _pam_log_debug(ctrl, LOG_INFO, "Verify user `%s'", username); #endif - } - if (ctrl & WINBIND_REQUIRED_MEMBERSHIP) { - - for ( i=0; i<argc; i++ ) { + member = get_member_from_config(argc, argv, ctrl); - if ((strncmp(argv[i], "require_membership_of", strlen("require_membership_of")) == 0) || - (strncmp(argv[i], "require-membership-of", strlen("require-membership-of")) == 0)) { + cctype = get_krb5_cc_type_from_config(argc, argv, ctrl); - char *p; - char *parm = strdup(argv[i]); + /* Now use the username to look up password */ + retval = winbind_auth_request(pamh, ctrl, username, password, member, cctype, True); - if ( (p = strchr( parm, '=' )) == NULL) { - _pam_log(LOG_INFO, "no \"=\" delimiter for \"require_membership_of\" found\n"); - break; - } + if (retval == PAM_NEW_AUTHTOK_REQD || + retval == PAM_AUTHTOK_EXPIRED) { - member = strdup(p+1); - } - } - } + char *buf; - /* Now use the username to look up password */ - retval = winbind_auth_request(username, password, member, ctrl); - if (retval == PAM_NEW_AUTHTOK_REQD || - retval == PAM_AUTHTOK_EXPIRED) { - - char *buf; - - if (!asprintf(&buf, "%d", retval)) { - return PAM_BUF_ERR; - } + if (!asprintf(&buf, "%d", retval)) { + return PAM_BUF_ERR; + } - pam_set_data( pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, (void *)buf, _pam_winbind_cleanup_func); + pam_set_data( pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, (void *)buf, _pam_winbind_cleanup_func); - return PAM_SUCCESS; - } - - return retval; + return PAM_SUCCESS; + } + + return retval; } PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { - 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_setcred"); + + if (flags & PAM_DELETE_CRED) { + return pam_sm_close_session(pamh, flags, argc, argv); + } + + return PAM_SUCCESS; } /* @@ -546,110 +874,234 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { - const char *username; - void *tmp = NULL; + const char *username; + int retval = PAM_USER_UNKNOWN; + void *tmp = NULL; + + /* parse arguments */ + int ctrl = _pam_parse(argc, argv); + if (ctrl == -1) { + return PAM_SYSTEM_ERR; + } - int retval = PAM_USER_UNKNOWN; + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_acct_mgmt"); - /* parse arguments */ - int ctrl = _pam_parse(argc, argv); - /* Get the username */ - retval = pam_get_user(pamh, &username, NULL); - if ((retval != PAM_SUCCESS) || (!username)) { - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_DEBUG,"can not get the username"); - return PAM_SERVICE_ERR; - } + /* Get the username */ + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + _pam_log_debug(ctrl, LOG_DEBUG,"can not get the username"); + return PAM_SERVICE_ERR; + } - /* Verify the username */ - retval = valid_user(username); - switch (retval) { + /* Verify the username */ + retval = valid_user(username); + switch (retval) { case -1: - /* some sort of system error. The log was already printed */ - return PAM_SERVICE_ERR; + /* some sort of system error. The log was already printed */ + return PAM_SERVICE_ERR; case 1: - /* the user does not exist */ - if (ctrl & WINBIND_DEBUG_ARG) - _pam_log(LOG_NOTICE, "user `%s' not found", - username); - if (ctrl & WINBIND_UNKNOWN_OK_ARG) - return PAM_IGNORE; - return PAM_USER_UNKNOWN; + /* the user does not exist */ + _pam_log_debug(ctrl, LOG_NOTICE, "user `%s' not found", username); + if (ctrl & WINBIND_UNKNOWN_OK_ARG) { + return PAM_IGNORE; + } + return PAM_USER_UNKNOWN; case 0: - pam_get_data( pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, (const void **)&tmp); - - if (tmp != NULL) { - retval = atoi(tmp); - switch (retval) { - case PAM_AUTHTOK_EXPIRED: - /* fall through, since new token is required in this case */ - case PAM_NEW_AUTHTOK_REQD: - _pam_log(LOG_WARNING, "pam_sm_acct_mgmt success but %s is set", - PAM_WINBIND_NEW_AUTHTOK_REQD); - _pam_log(LOG_NOTICE, "user '%s' needs new password", username); - /* PAM_AUTHTOKEN_REQD does not exist, but is documented in the manpage */ - return PAM_NEW_AUTHTOK_REQD; - default: - _pam_log(LOG_WARNING, "pam_sm_acct_mgmt success"); - _pam_log(LOG_NOTICE, "user '%s' granted access", username); - return PAM_SUCCESS; - } - } - - /* Otherwise, the authentication looked good */ - _pam_log(LOG_NOTICE, "user '%s' granted access", username); - return PAM_SUCCESS; + pam_get_data( pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, (const void **)&tmp); + if (tmp != NULL) { + retval = atoi(tmp); + switch (retval) { + case PAM_AUTHTOK_EXPIRED: + /* fall through, since new token is required in this case */ + case PAM_NEW_AUTHTOK_REQD: + _pam_log(LOG_WARNING, "pam_sm_acct_mgmt success but %s is set", + PAM_WINBIND_NEW_AUTHTOK_REQD); + _pam_log(LOG_NOTICE, "user '%s' needs new password", username); + /* PAM_AUTHTOKEN_REQD does not exist, but is documented in the manpage */ + return PAM_NEW_AUTHTOK_REQD; + default: + _pam_log(LOG_WARNING, "pam_sm_acct_mgmt success"); + _pam_log(LOG_NOTICE, "user '%s' granted access", username); + return PAM_SUCCESS; + } + } + + /* Otherwise, the authentication looked good */ + _pam_log(LOG_NOTICE, "user '%s' granted access", username); + return PAM_SUCCESS; default: - /* we don't know anything about this return value */ - _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'", - retval, username); - return PAM_SERVICE_ERR; - } - - /* should not be reached */ - return PAM_IGNORE; + /* we don't know anything about this return value */ + _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s')", + retval, username); + return PAM_SERVICE_ERR; + } + + /* should not be reached */ + return PAM_IGNORE; } + PAM_EXTERN int pam_sm_open_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_open_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_open_session handler"); + + + if (ctrl & WINBIND_CREATE_HOMEDIR) { + + struct passwd *pwd = NULL; + const char *username; + int ret; + fstring tok; + fstring create_dir; + SMB_STRUCT_STAT sbuf; + + /* Get the username */ + ret = pam_get_user(pamh, &username, NULL); + if ((ret != PAM_SUCCESS) || (!username)) { + _pam_log_debug(ctrl, LOG_DEBUG, "can not get the username"); + return PAM_SERVICE_ERR; + } + + pwd = getpwnam(username); + if (pwd == NULL) { + _pam_log_debug(ctrl, LOG_DEBUG, "can not get the username"); + return PAM_SERVICE_ERR; + } + + _pam_log_debug(ctrl, LOG_DEBUG, "homedir is: %s", pwd->pw_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; /* <DO NOT free() THESE> */ const char *user; - const char *member = NULL; char *pass_old, *pass_new; /* </DO NOT free() THESE> */ - 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 <tridge@samba.org> 2000 * Copyright (c) Tim Potter <tpot@samba.org> 2000 * Copyright (c) Andrew Bartlettt <abartlet@samba.org> 2002 + * Copyright (c) Guenther Deschner <gd@samba.org> 2005-2006 * Copyright (c) Jan Rêkorajski 1999. * Copyright (c) Andrew G. Morgan 1996-8. * Copyright (c) Alex O. Yuriev, 1996. diff --git a/source3/nsswitch/pam_winbind.h b/source3/nsswitch/pam_winbind.h index 86ba977287..1e38269e0e 100644 --- a/source3/nsswitch/pam_winbind.h +++ b/source3/nsswitch/pam_winbind.h @@ -17,6 +17,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <errno.h> +#include <time.h> #include <config.h> @@ -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/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index fcab76b033..ff0f15a122 100644 --- a/source3/nsswitch/wb_client.c +++ b/source3/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/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 793a05f179..571a1b3e19 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/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" }, @@ -1016,6 +1100,11 @@ int main(int argc, char **argv) #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 POPT_TABLEEND @@ -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/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index bbcf2b5e88..4a269bac17 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/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/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 00a0233055..e81102571c 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/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/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index 29129e823a..a866365042 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/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/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 9ecfb1ff6e..28633757c0 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/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; @@ -188,6 +171,22 @@ static uint32 centry_uint32(struct cache_entry *centry) } /* + 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 */ static uint8 centry_uint8(struct cache_entry *centry) @@ -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", @@ -522,6 +583,16 @@ static void centry_put_uint32(struct cache_entry *centry, uint32 v) } /* + 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 */ static void centry_put_uint8(struct cache_entry *centry, uint8 v) @@ -563,6 +634,28 @@ static void centry_put_sid(struct cache_entry *centry, const DOM_SID *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() */ struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status) @@ -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/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 177ac54d3e..568078f86e 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/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/source3/nsswitch/winbindd_cred_cache.c b/source3/nsswitch/winbindd_cred_cache.c new file mode 100644 index 0000000000..a8aab04031 --- /dev/null +++ b/source3/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/source3/nsswitch/winbindd_creds.c b/source3/nsswitch/winbindd_creds.c new file mode 100644 index 0000000000..d37e9019db --- /dev/null +++ b/source3/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/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c index 38030ee9ac..1988f36b51 100644 --- a/source3/nsswitch/winbindd_dual.c +++ b/source3/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/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index ff2d19f5fc..a328cebac4 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/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/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c index 1fbf4b33df..b6aecae393 100644 --- a/source3/nsswitch/winbindd_misc.c +++ b/source3/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; i<num_domains; i++) { + if (strequal(names[i], domain->name)) { + 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/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index eda68ae5c7..033e51d794 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/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/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c index 890007ae38..ab20102f79 100644 --- a/source3/nsswitch/winbindd_pam.c +++ b/source3/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/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c index c32aa01a38..96a85a4f3a 100644 --- a/source3/nsswitch/winbindd_passdb.c +++ b/source3/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; i<num_members; i++) { @@ -265,19 +266,24 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, char **name, enum SID_NAME_USE *type) { - struct acct_info info; + const char *dom, *nam; DEBUG(10, ("Converting SID %s\n", sid_string_static(sid))); - if (!pdb_get_aliasinfo(sid, &info)) + /* Paranoia check */ + if (!sid_check_is_in_builtin(sid) && + !sid_check_is_in_our_domain(sid)) { + DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with " + "passdb backend\n", sid_string_static(sid))); return NT_STATUS_NONE_MAPPED; + } - *domain_name = talloc_strdup(mem_ctx, domain->name); - *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; i<num_members; i++) { + DOM_SID *sid = &((*sid_mem)[i]); + sid_copy(sid, &domain->sid); + 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; i<num_members; i++) { + if (lsa_names[i].type != SID_NAME_USER) { + DEBUG(2, ("Got %s as group member -- ignoring\n", + sid_type_lookup(lsa_names[i].type))); + continue; + } + (*names)[i] = talloc_steal((*names), + lsa_names[i].name); + (*name_types)[i] = lsa_names[i].type; + + num_mapped += 1; + } + + *num_names = num_mapped; + return NT_STATUS_OK; } /* find the sequence number for a domain */ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) { - *seq = 1; + BOOL result; + time_t seq_num; + + result = pdb_get_seq_num(&seq_num); + if (!result) { + *seq = 1; + } + + *seq = (int) seq_num; + /* *seq = 1; */ return NT_STATUS_OK; } +static NTSTATUS lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_12 *lockout_policy) +{ + /* actually we have that */ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + SAM_UNK_INFO_1 *password_policy) +{ + /* actually we have that */ + return NT_STATUS_NOT_IMPLEMENTED; +} + /* get a list of trusted domains */ static NTSTATUS trusted_domains(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, @@ -341,41 +437,35 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, DOM_SID **dom_sids) { NTSTATUS nt_status; - int enum_ctx = 0; - int num_sec_domains; - TRUSTDOM **domains; + struct trustdom_info **domains; + int i; + *num_domains = 0; *names = NULL; *alt_names = NULL; *dom_sids = NULL; - do { - int i; - nt_status = secrets_get_trusted_domains(mem_ctx, &enum_ctx, 1, - &num_sec_domains, - &domains); - *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names, char *, - num_sec_domains + *num_domains); - *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names, char *, - num_sec_domains + *num_domains); - *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids, DOM_SID, - num_sec_domains + *num_domains); - - for (i=0; i< num_sec_domains; i++) { - if (pull_ucs2_talloc(mem_ctx, &(*names)[*num_domains], - domains[i]->name) == -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/source3/nsswitch/winbindd_reconnect.c b/source3/nsswitch/winbindd_reconnect.c index 77df9c1513..e37bfcad97 100644 --- a/source3/nsswitch/winbindd_reconnect.c +++ b/source3/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/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index 6179189e30..4aaedad4a2 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/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/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index fc878cb5cc..a4cd8f7604 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/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/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 0b88d5eee5..9670bf534c 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/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/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 4c3306a8ac..b92ee0de82 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/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/source3/pam_smbpass/pam_smb_auth.c b/source3/pam_smbpass/pam_smb_auth.c index 70275abf92..cbdb6fa811 100644 --- a/source3/pam_smbpass/pam_smb_auth.c +++ b/source3/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/source3/pam_smbpass/pam_smb_passwd.c b/source3/pam_smbpass/pam_smb_passwd.c index 8149bc1200..176b278c04 100644 --- a/source3/pam_smbpass/pam_smb_passwd.c +++ b/source3/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/source3/pam_smbpass/support.c b/source3/pam_smbpass/support.c index 3f2c638816..add74acc5d 100644 --- a/source3/pam_smbpass/support.c +++ b/source3/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/source3/param/loadparm.c b/source3/param/loadparm.c index a2aa851b09..a886728047 100644 --- a/source3/param/loadparm.c +++ b/source3/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) { @@ -4190,6 +4241,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/source3/param/params.c b/source3/param/params.c index 2a6c8b3e65..f5ce6bdb64 100644 --- a/source3/param/params.c +++ b/source3/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/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 4640eb6ae5..6266aa9cab 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/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; i<num_rids; i++) { + DOM_SID sid; + + sid_copy(&sid, domain_sid); + sid_append_rid(&sid, rids[i]); + + if (winbind_lookup_sid(mem_ctx, &sid, + *domain_name == NULL ? + domain_name : NULL, + &names[i], &types[i])) { + if ((names[i] == NULL) || ((*domain_name) == NULL)) { + return False; + } + } else { + types[i] = SID_NAME_UNKNOWN; + } + } + return True; +} -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) +static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, + int num_rids, uint32_t *rids, + const char **domain_name, + const char ***names, enum SID_NAME_USE **types) { - const char *domain = NULL; - const char *name = NULL; - enum SID_NAME_USE type; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + int i; - /* Check if this is our own sid. This should perhaps be done by - winbind? For the moment handle it here. */ + *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids); + *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids); - if (tmp_ctx == NULL) { - DEBUG(0, ("talloc_new failed\n")); + if ((*names == NULL) || (*types == NULL)) { return False; } - if (sid_check_is_domain(sid)) { - domain = talloc_strdup(tmp_ctx, get_global_sam_name()); - name = talloc_strdup(tmp_ctx, ""); - type = SID_NAME_DOMAIN; - goto ok; + if (sid_check_is_domain(domain_sid)) { + NTSTATUS result; + + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, get_global_sam_name()); + } + + if (*domain_name == NULL) { + return False; + } + + become_root(); + result = pdb_lookup_rids(domain_sid, num_rids, rids, + *names, *types); + unbecome_root(); + + return (NT_STATUS_IS_OK(result) || + NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) || + NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)); } - if (sid_check_is_in_our_domain(sid)) { - uint32 rid; - SMB_ASSERT(sid_peek_rid(sid, &rid)); + if (sid_check_is_builtin(domain_sid)) { - /* For our own domain passdb is responsible */ - if (!lookup_global_sam_rid(tmp_ctx, rid, &name, &type)) { - goto failed; + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, builtin_domain_name()); } - domain = talloc_strdup(tmp_ctx, get_global_sam_name()); - goto ok; + if (*domain_name == NULL) { + return False; + } + + for (i=0; i<num_rids; i++) { + if (lookup_builtin_rid(*names, rids[i], + &(*names)[i])) { + if ((*names)[i] == NULL) { + return False; + } + (*types)[i] = SID_NAME_ALIAS; + } else { + (*types)[i] = SID_NAME_UNKNOWN; + } + } + return True; + } + + if (sid_check_is_wellknown_domain(domain_sid, NULL)) { + for (i=0; i<num_rids; i++) { + DOM_SID sid; + sid_copy(&sid, domain_sid); + sid_append_rid(&sid, rids[i]); + if (lookup_wellknown_sid(mem_ctx, &sid, + domain_name, &(*names)[i])) { + if ((*names)[i] == NULL) { + return False; + } + (*types)[i] = SID_NAME_WKN_GRP; + } else { + (*types)[i] = SID_NAME_UNKNOWN; + } + } + return True; + } + + if (sid_check_is_unix_users(domain_sid)) { + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, unix_users_domain_name()); + } + for (i=0; i<num_rids; i++) { + (*names)[i] = talloc_strdup( + (*names), uidtoname(rids[i])); + (*types)[i] = SID_NAME_USER; + } + return True; + } + + if (sid_check_is_unix_groups(domain_sid)) { + if (*domain_name == NULL) { + *domain_name = talloc_strdup( + mem_ctx, unix_groups_domain_name()); + } + for (i=0; i<num_rids; i++) { + (*names)[i] = talloc_strdup( + (*names), gidtoname(rids[i])); + (*types)[i] = SID_NAME_DOM_GRP; + } + return True; + } + + return winbind_lookup_rids(mem_ctx, domain_sid, num_rids, rids, + domain_name, *names, *types); +} + +/* + * Is the SID a domain as such? If yes, lookup its name. + */ + +static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx, + const char **name) +{ + const char *tmp; + enum SID_NAME_USE type; + + if (sid_check_is_domain(sid)) { + *name = talloc_strdup(mem_ctx, get_global_sam_name()); + return True; } if (sid_check_is_builtin(sid)) { + *name = talloc_strdup(mem_ctx, builtin_domain_name()); + return True; + } - domain = talloc_strdup(tmp_ctx, builtin_domain_name()); + if (sid_check_is_wellknown_domain(sid, &tmp)) { + *name = talloc_strdup(mem_ctx, tmp); + return True; + } - /* Yes, W2k3 returns "BUILTIN" both as domain and name here */ - name = talloc_strdup(tmp_ctx, builtin_domain_name()); - type = SID_NAME_DOMAIN; - goto ok; + if (sid->num_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; i<num_domains; i++) { + if (sid_equal(sid, &domains[i]->sid)) { + *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; i<num_sids; i++) { + DOM_SID sid; + uint32 rid; + const char *domain_name = NULL; + + sid_copy(&sid, sids[i]); + name_infos[i].type = SID_NAME_USE_NONE; + + if (lookup_as_domain(&sid, name_infos, &domain_name)) { + /* We can't push that through the normal lookup + * process, as this would reference illegal + * domains. + * + * For example S-1-5-32 would end up referencing + * domain S-1-5- with RID 32 which is clearly wrong. + */ + if (domain_name == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + name_infos[i].rid = 0; + name_infos[i].type = SID_NAME_DOMAIN; + name_infos[i].name = NULL; + + if (sid_check_is_builtin(&sid)) { + /* Yes, W2k3 returns "BUILTIN" both as domain + * and name here */ + name_infos[i].name = talloc_strdup( + name_infos, builtin_domain_name()); + if (name_infos[i].name == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + } + } else { + /* This is a normal SID with rid component */ + if (!sid_split_rid(&sid, &rid)) { + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + } + + if (!check_dom_sid_to_level(&sid, level)) { + name_infos[i].rid = 0; + name_infos[i].type = SID_NAME_UNKNOWN; + name_infos[i].name = NULL; + continue; + } + + for (j=0; j<MAX_REF_DOMAINS; j++) { + if (!dom_infos[j].valid) { + break; + } + if (sid_equal(&sid, &dom_infos[j].sid)) { + break; + } + } + + if (j == MAX_REF_DOMAINS) { + /* TODO: What's the right error message here? */ + result = NT_STATUS_NONE_MAPPED; + goto done; + } + + if (!dom_infos[j].valid) { + /* We found a domain not yet referenced, create a new + * ref. */ + dom_infos[j].valid = True; + sid_copy(&dom_infos[j].sid, &sid); + + if (domain_name != NULL) { + /* This name was being found above in the case + * when we found a domain SID */ + dom_infos[j].name = + talloc_steal(dom_infos, domain_name); + } else { + /* lookup_rids will take care of this */ + dom_infos[j].name = NULL; + } + } + + name_infos[i].dom_idx = j; + + if (name_infos[i].type == SID_NAME_USE_NONE) { + name_infos[i].rid = rid; + + ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs, + &dom_infos[j].num_idxs); + + if (dom_infos[j].idxs == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + } + } + + /* Iterate over the domains found */ + + for (i=0; i<MAX_REF_DOMAINS; i++) { + uint32_t *rids; + const char **names; + enum SID_NAME_USE *types; + struct lsa_dom_info *dom = &dom_infos[i]; + + if (!dom->valid) { + /* 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; j<dom->num_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; j<dom->num_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/source3/passdb/machine_sid.c b/source3/passdb/machine_sid.c index 074a516bcb..d7cae06749 100644 --- a/source3/passdb/machine_sid.c +++ b/source3/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/source3/passdb/passdb.c b/source3/passdb/passdb.c index f9f6021d81..90a51d1cbd 100644 --- a/source3/passdb/passdb.c +++ b/source3/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. @@ -732,129 +837,11 @@ BOOL algorithmic_pdb_rid_is_user(uint32 rid) } /******************************************************************* - 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/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c index 783e9e23fa..71fb36e0d5 100644 --- a/source3/passdb/pdb_get_set.c +++ b/source3/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/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 4808af3908..d8afff2111 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/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<num_uids; i++) { DOM_SID sid; - if (!NT_STATUS_IS_OK(uid_to_sid(&sid, uids[i]))) { - DEBUG(1, ("Could not map member uid to SID\n")); - continue; - } + uid_to_sid(&sid, uids[i]); if (!sid_check_is_in_our_domain(&sid)) { DEBUG(1, ("Inconsistent SAM -- group member uid not " @@ -1676,6 +1920,92 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, return NT_STATUS_OK; } +/******************************************************************* + Look up a rid in the SAM we're responsible for (i.e. passdb) + ********************************************************************/ + +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) +{ + 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)) { + struct passwd *pw; + + 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); + + 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/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index b35ce18eee..a21e976803 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/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=<domain-sid>*)) 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; i<num_members; i++) filter = talloc_asprintf(mem_ctx, "%s(sambaSIDList=%s)", @@ -3331,7 +3453,9 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods, return NT_STATUS_OK; } -static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, int policy_index, uint32 value) +static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, + int policy_index, + uint32 value) { NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; int rc; @@ -3352,7 +3476,8 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, policy_attr = get_account_policy_attr(policy_index); if (policy_attr == NULL) { - DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid policy\n")); + DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid " + "policy\n")); return ntstatus; } @@ -3363,40 +3488,39 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods, smbldap_set_mod(&mods, LDAP_MOD_REPLACE, policy_attr, value_string); - rc = smbldap_modify(ldap_state->smbldap_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; i<num_rids; i++) attrs[i] = SID_NAME_UNKNOWN; - allsids = SMB_STRDUP(""); - if (allsids == NULL) return NT_STATUS_NO_MEMORY; + allsids = talloc_strdup(mem_ctx, ""); + if (allsids == NULL) { + goto done; + } for (i=0; i<num_rids; i++) { DOM_SID sid; sid_copy(&sid, domain_sid); sid_append_rid(&sid, rids[i]); - tmp = allsids; - asprintf(&allsids, "%s(sambaSid=%s)", allsids, - sid_string_static(&sid)); - if (allsids == NULL) return NT_STATUS_NO_MEMORY; - free(tmp); + allsids = talloc_asprintf_append(allsids, "(sambaSid=%s)", + sid_string_static(&sid)); + if (allsids == NULL) { + goto done; + } } /* First look for users */ @@ -3577,40 +3708,43 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, char *filter; const char *ldap_attrs[] = { "uid", "sambaSid", NULL }; - asprintf(&filter, ("(&(objectClass=sambaSamAccount)(|%s))"), - allsids); - if (filter == NULL) return NT_STATUS_NO_MEMORY; + filter = talloc_asprintf( + mem_ctx, ("(&(objectClass=sambaSamAccount)(|%s))"), + allsids); + + if (filter == NULL) { + goto done; + } rc = smbldap_search(ldap_state->smbldap_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 : "<NULL>")); 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/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c index cf2d1d7c8a..49c3c9db06 100644 --- a/source3/passdb/pdb_nds.c +++ b/source3/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/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index 487df96e95..06a3f4f4a1 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/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/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 370c8adc7d..74f47e70dc 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/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/source3/passdb/secrets.c b/source3/passdb/secrets.c index 88dabbd644..69bafc7ce5 100644 --- a/source3/passdb/secrets.c +++ b/source3/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/source3/passdb/util_builtin.c b/source3/passdb/util_builtin.c index 12a98d24dd..9c59df1f68 100644 --- a/source3/passdb/util_builtin.c +++ b/source3/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/source3/passdb/util_unixsids.c b/source3/passdb/util_unixsids.c new file mode 100644 index 0000000000..ee8cf2d8f0 --- /dev/null +++ b/source3/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/source3/passdb/util_wellknown.c b/source3/passdb/util_wellknown.c index 8caae3b2a0..be3cf37446 100644 --- a/source3/passdb/util_wellknown.c +++ b/source3/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/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index a91c2a5c70..e6c6f7d3dc 100644 --- a/source3/printing/nt_printing.c +++ b/source3/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/source3/printing/print_generic.c b/source3/printing/print_generic.c index b2484d5b43..18fca67860 100644 --- a/source3/printing/print_generic.c +++ b/source3/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/source3/python/py_lsa.c b/source3/python/py_lsa.c index 4f809520bc..a4e8254e0d 100644 --- a/source3/python/py_lsa.c +++ b/source3/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/source3/rpc_client/cli_dfs.c b/source3/rpc_client/cli_dfs.c index 78df220ac2..8b94d6ed9d 100644 --- a/source3/rpc_client/cli_dfs.c +++ b/source3/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/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index aa1cb95fda..9331d09093 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/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/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index b5addf3375..3dc26f61c9 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/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/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 23c66acf26..9cc350bef1 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/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/source3/rpc_client/cli_samr.c b/source3/rpc_client/cli_samr.c index fb95da97ae..744d8174a0 100644 --- a/source3/rpc_client/cli_samr.c +++ b/source3/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/source3/rpc_parse/parse_dfs.c b/source3/rpc_parse/parse_dfs.c index f102e95004..f1d0705302 100644 --- a/source3/rpc_parse/parse_dfs.c +++ b/source3/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)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - - if(!prs_align(ps)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - - if(!prs_uint32("ptr_ServerName", ps, depth, &q_d->ptr_ServerName)) + + + if (!prs_uint32("state", ps, depth, &v->state)) 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("num_stores", ps, depth, &v->num_stores)) return False; + + return True; +} - if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName)) +BOOL netdfs_io_dfs_Info2_d(const char *desc, NETDFS_DFS_INFO2 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(q_d->ptr_ShareName) - if (!smb_io_unistr2("ShareName",&q_d->ShareName, q_d->ptr_ShareName, ps, depth)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info2_d"); + depth++; + if (v->ptr0_path) { + if (!prs_align_custom(ps, 4)) return False; - if(!prs_align(ps)) - 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; } -/******************************************************************* -Read/write a DFS_R_DFS_REMOVE structure -*******************************************************************/ +BOOL init_netdfs_dfs_StorageInfo(NETDFS_DFS_STORAGEINFO *v, uint32 state, const char *server, const char *share) +{ + 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 { + 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 dfs_io_r_dfs_remove(const char *desc, DFS_R_DFS_REMOVE *r_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(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_StorageInfo_p"); depth++; - - if(!prs_werror("status", ps, depth, &r_d->status)) + if (!prs_uint32("state", ps, depth, &v->state)) return False; - + + if (!prs_uint32("ptr0_server", ps, depth, &v->ptr0_server)) + return False; + + + if (!prs_uint32("ptr0_share", ps, depth, &v->ptr0_share)) + return False; + + return True; } -/******************************************************************* -Make a DFS_Q_DFS_ADD structure -*******************************************************************/ +BOOL netdfs_io_dfs_StorageInfo_d(const char *desc, NETDFS_DFS_STORAGEINFO *v, prs_struct *ps, int depth) +{ + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_StorageInfo_d"); + depth++; + + 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_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_Info3(NETDFS_DFS_INFO3 *v, const char *path, const char *comment, uint32 state, uint32 num_stores, NETDFS_DFS_STORAGEINFO **stores) { - 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_Info3\n")); + + if (path) { + v->ptr0_path = 1; + init_unistr2(&v->path, path, UNI_FLAGS_NONE); } else { - q_d->ptr_Comment = 0; + v->ptr0_path = 0; } - - q_d->Flags = flags; + + 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_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_Info3_p(const char *desc, NETDFS_DFS_INFO3 *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_Info3_p"); depth++; - - if(!prs_align(ps)) + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - - if(!smb_io_unistr2("DfsEntryPath",&q_d->DfsEntryPath, 1, ps, depth)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - if(!prs_align(ps)) + + + if (!prs_uint32("state", ps, depth, &v->state)) return False; - - if(!smb_io_unistr2("ServerName",&q_d->ServerName, 1, ps, depth)) + + if (!prs_uint32("num_stores", ps, depth, &v->num_stores)) return False; - if(!prs_align(ps)) + + if (!prs_uint32("ptr0_stores", ps, depth, &v->ptr0_stores)) return False; + + + return True; +} + +BOOL netdfs_io_dfs_Info3_d(const char *desc, NETDFS_DFS_INFO3 *v, prs_struct *ps, int depth) +{ + 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_1<v->num_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_1<v->num_stores;i_stores_1++) { + if (!netdfs_io_dfs_StorageInfo_d("stores", &v->stores[i_stores_1], ps, depth)) + return False; + } + } + + return True; +} - if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName)) +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) +{ + 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; +} + +BOOL netdfs_io_dfs_Info4_p(const char *desc, NETDFS_DFS_INFO4 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(!smb_io_unistr2("ShareName",&q_d->ShareName, 1, ps, depth)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info4_p"); + depth++; + if (!prs_uint32("ptr0_path", ps, depth, &v->ptr0_path)) return False; - if(!prs_align(ps)) + + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) 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("timeout", ps, depth, &v->timeout)) return False; - if(!prs_align(ps)) + + if (!smb_io_uuid("guid", &v->guid, ps, depth)) return False; + + if (!prs_uint32("num_stores", ps, depth, &v->num_stores)) + return False; + + if (!prs_uint32("ptr0_stores", ps, depth, &v->ptr0_stores)) + return False; + + + return True; +} - if(!prs_uint32("Flags", ps, depth, &q_d->Flags)) - return True; - +BOOL netdfs_io_dfs_Info4_d(const char *desc, NETDFS_DFS_INFO4 *v, prs_struct *ps, int depth) +{ + 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_stores_1=0; i_stores_1<v->num_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_1<v->num_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_ADD 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_add(const char *desc, DFS_R_DFS_ADD *r_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_Info100_p(const char *desc, NETDFS_DFS_INFO100 *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_Info100_p"); depth++; - - if(!prs_werror("status", ps, depth, &r_d->status)) + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) 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 netdfs_io_dfs_Info100_d(const char *desc, NETDFS_DFS_INFO100 *v, prs_struct *ps, int depth) { - 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; + 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; } -/************************************************************ - Read/write a DFS_Q_GET_INFO structure - ************************************************************/ +BOOL init_netdfs_dfs_Info101(NETDFS_DFS_INFO101 *v, uint32 state) +{ + DEBUG(5,("init_netdfs_dfs_Info101\n")); + + v->state = state; + + return True; +} -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_Info101_p(const char *desc, NETDFS_DFS_INFO101 *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_Info101_p"); depth++; - - if(!smb_io_unistr2("",&q_i->uni_path, 1, ps, depth)) + if (!prs_uint32("state", ps, depth, &v->state)) return False; + + return True; +} - if(!prs_align(ps)) +BOOL netdfs_io_dfs_Info101_d(const char *desc, NETDFS_DFS_INFO101 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info101_d"); + depth++; + + return True; +} - if(!prs_uint32("ptr_server", ps, depth, &q_i->ptr_server)) +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; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info102_p"); + depth++; + if (!prs_uint32("timeout", ps, depth, &v->timeout)) + return False; + + return True; +} - 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)) +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; +} - if(!prs_uint32("ptr_share", ps, depth, &q_i->ptr_share)) +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; +} + +BOOL netdfs_io_dfs_Info200_p(const char *desc, NETDFS_DFS_INFO200 *v, prs_struct *ps, int depth) +{ + if (v == NULL) 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)) + + 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; +} - if(!prs_uint32("level", ps, depth, &q_i->level)) +BOOL netdfs_io_dfs_Info200_d(const char *desc, NETDFS_DFS_INFO200 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info200_d"); + depth++; + 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; } -/************************************************************ - Read/write a DFS_R_GET_INFO structure - ************************************************************/ +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; +} -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_Info300_p(const char *desc, NETDFS_DFS_INFO300 *v, prs_struct *ps, int depth) { - if(r_i == NULL) + if (v == NULL) return False; - - if(!prs_uint32("level", ps, depth, &r_i->level)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_Info300_p"); + depth++; + if (!prs_uint32("flags", ps, depth, &v->flags)) return False; - if(!prs_uint32("ptr_ctr", ps, depth, &r_i->ptr_ctr)) + + if (!prs_uint32("ptr0_dom_root", ps, depth, &v->ptr0_dom_root)) return False; + + + return True; +} - if(!dfs_io_dfs_info_ctr("", &r_i->ctr, 1, r_i->level, ps, depth)) +BOOL netdfs_io_dfs_Info300_d(const char *desc, NETDFS_DFS_INFO300 *v, prs_struct *ps, int depth) +{ + if (v == NULL) return False; - if(!prs_werror("status", ps, depth, &r_i->status)) + + 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 (!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; } - -/************************************************************ - 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_EnumArray1(NETDFS_DFS_ENUMARRAY1 *v, uint32 count, NETDFS_DFS_INFO1 **s) { - 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_EnumArray1\n")); + + v->count = count; + + if (s) { + v->ptr0_s = 1; + v->s = *s; + } else { + v->ptr0_s = 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_EnumArray1_p(const char *desc, NETDFS_DFS_ENUMARRAY1 *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_EnumArray1_p"); depth++; - - if(!prs_align(ps)) + if (!prs_uint32("count", ps, depth, &v->count)) return False; - - if(!prs_uint32("level", ps, depth, &q_d->level)) + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) return False; - if(!prs_uint32("maxpreflen", ps, depth, &q_d->maxpreflen)) + + + 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; - if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer)) + + 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_1<v->count;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_1<v->count;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; - if(!prs_uint32("level2", ps, depth, &q_d->level2)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray2_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) return False; - if(!prs_uint32("level3", ps, depth, &q_d->level2)) + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) return False; - - if(!prs_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries)) + + + 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; - if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries)) + + 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_1<v->count;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_1<v->count;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; - if(!prs_uint32("num_entries2", ps, depth, &q_d->num_entries2)) + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumArray3_p"); + depth++; + if (!prs_uint32("count", ps, depth, &v->count)) return False; - if(!smb_io_enum_hnd("resume_hnd",&q_d->reshnd, ps, depth)) + + if (!prs_uint32("ptr0_s", ps, depth, &v->ptr0_s)) 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_EnumArray3_d(const char *desc, NETDFS_DFS_ENUMARRAY3 *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; + 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=0;i<num_entries;i++) { - if(!prs_uint32("ptr_entrypath",ps, depth, &ctr->dfs.info1[i].ptr_entrypath)) + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info3_p("s", &v->s[i_s_1], ps, depth)) return False; } - for(i=0;i<num_entries;i++) { - if(!smb_io_unistr2("", &ctr->dfs.info1[i].entrypath, ctr->dfs.info1[i].ptr_entrypath, ps, depth)) + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info3_d("s", &v->s[i_s_1], ps, depth)) return False; - if(!prs_align(ps)) + } + } + + 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_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info4_p("s", &v->s[i_s_1], ps, depth)) 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) + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info4_d("s", &v->s[i_s_1], ps, depth)) return False; } + } + + return True; +} - for(i=0;i<num_entries;i++) { - if(!prs_uint32("ptr_entrypath", ps, depth, &ctr->dfs.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; +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=0;i<num_entries;i++) { - if(!smb_io_unistr2("", &ctr->dfs.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)) + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info200_p("s", &v->s[i_s_1], ps, depth)) 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) + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info200_d("s", &v->s[i_s_1], ps, depth)) return False; } + } + + return True; +} - for(i=0;i<num_entries;i++) { - if(!prs_uint32("ptr_entrypath", ps, depth, &ctr->dfs.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)) +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_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info300_p("s", &v->s[i_s_1], ps, depth)) return False; - if(!prs_uint32("ptr_storages", ps, depth, &ctr->dfs.info3[i].ptr_storages)) + } + for (i_s_1=0; i_s_1<v->count;i_s_1++) { + if (!netdfs_io_dfs_Info300_d("s", &v->s[i_s_1], ps, depth)) return False; } - for(i=0;i<num_entries;i++) { - if(!smb_io_unistr2("", &ctr->dfs.info3[i].entrypath, ctr->dfs.info3[i].ptr_entrypath, ps, depth)) + } + + 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; - if(!prs_align(ps)) + + depth--; + break; + + case 2: + depth++; + if (!prs_uint32("ptr0_info2", ps, depth, &v->ptr0)) return False; - if(!smb_io_unistr2("", &ctr->dfs.info3[i].comment, ctr->dfs.info3[i].ptr_comment, ps, depth)) + + depth--; + break; + + case 3: + depth++; + if (!prs_uint32("ptr0_info3", ps, depth, &v->ptr0)) return False; - if(!prs_align(ps)) + + depth--; + break; + + case 4: + depth++; + if (!prs_uint32("ptr0_info4", ps, depth, &v->ptr0)) return False; - if(!prs_uint32("num_storage_infos", ps, depth, &ctr->dfs.info3[i].num_storage_infos)) + + depth--; + break; + + case 200: + depth++; + if (!prs_uint32("ptr0_info200", ps, depth, &v->ptr0)) return False; - - if(!dfs_io_dfs_storage_info("storage_info", &ctr->dfs.info3[i], ps, depth)) + + 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; } -/************************************************************ - Read/write a DFS_R_DFS_ENUM structure - ************************************************************/ +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 dfs_io_r_dfs_enum(const char *desc, DFS_R_DFS_ENUM *q_d, prs_struct *ps, int depth) +BOOL netdfs_io_dfs_EnumStruct_d(const char *desc, NETDFS_DFS_ENUMSTRUCT *v, prs_struct *ps, int depth) { - DFS_INFO_CTR *ctr; - if(q_d == NULL) + if (v == NULL) + return False; + + prs_debug(ps, depth, desc, "netdfs_io_dfs_EnumStruct_d"); + depth++; + + if (!prs_align_custom(ps, 4)) return False; - ctr = q_d->ctr; - if(ctr == NULL) + + if (!netdfs_io_dfs_EnumInfo_d("e", &v->e, ps, depth)) return False; + + return True; +} - prs_debug(ps, depth, desc, "dfs_io_r_dfs_enum"); +/* 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; +} - if(!prs_align(ps)) +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; +} - if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer)) +BOOL netdfs_io_r_dfs_GetManagerVersion(const char *desc, NETDFS_R_DFS_GETMANAGERVERSION *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_r_dfs_GetManagerVersion"); + depth++; + if (!prs_uint32("exist_flag", ps, depth, &v->exist_flag)) return False; - if(!prs_uint32("level2", ps, depth, &ctr->switch_value)) + + 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_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries)) + + if (!prs_align_custom(ps, 4)) return False; - if(q_d->ptr_num_entries) - if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries)) + + 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_uint32("ptr_num_entries2", ps, depth, &q_d->ptr_num_entries2)) + } + + if (!prs_align_custom(ps, 4)) + return False; + + if (!prs_uint32("ptr0_comment", ps, depth, &v->ptr0_comment)) return False; - if(q_d->ptr_num_entries2) - if(!prs_uint32("num_entries2", ps, depth, &ctr->num_entries)) + + 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; +} - if(!dfs_io_dfs_info_ctr("", ctr, q_d->num_entries, q_d->level, ps, depth)) +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; +} - if(!smb_io_enum_hnd("resume_hnd", &q_d->reshnd, ps, depth)) +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(!prs_werror("status", ps, depth, &q_d->status)) + + 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 dfs_io_dfs_storage_info(const char *desc, DFS_INFO_3* info3, prs_struct *ps, int depth) +BOOL init_netdfs_r_dfs_Remove(NETDFS_R_DFS_REMOVE *v, const char *path, const char *server, const char *share, WERROR status) { - int i=0; - if(info3 == NULL) + 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, "smb_io_dfs_storage_info"); + + prs_debug(ps, depth, desc, "netdfs_io_r_dfs_Remove"); depth++; + if (!prs_werror("status", ps, depth, &v->status)) + return False; + + return True; +} - if(UNMARSHALLING(ps)) { - info3->storages = PRS_ALLOC_MEM(ps, DFS_STORAGE_INFO, info3->num_storage_infos); - if (!info3->storages) - return False; +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; +} - for(i=0;i<info3->num_storage_infos;i++) { - if(!prs_uint32("storage_state", ps, depth, &info3->storages[i].state)) +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(!prs_uint32("ptr_servername", ps, depth, &info3->storages[i].ptr_servername)) + + if (!smb_io_unistr2("server", &v->server, 1, ps, depth)) return False; - if(!prs_uint32("ptr_sharename", ps, depth, &info3->storages[i].ptr_sharename)) + } + + 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; +} - for(i=0;i<info3->num_storage_infos;i++) { - if(!smb_io_unistr2("servername", &info3->storages[i].servername, info3->storages[i].ptr_servername, ps, depth)) +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(!prs_align(ps)) + if (!netdfs_io_dfs_EnumStruct_d("info", &v->info, ps, depth)) return False; - if(!smb_io_unistr2("sharename", &info3->storages[i].sharename, info3->storages[i].ptr_sharename, ps, depth)) + } + + 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(ps)) + } + + 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/source3/rpc_parse/parse_lsa.c b/source3/rpc_parse/parse_lsa.c index 3d28b657f3..1edc017510 100644 --- a/source3/rpc_parse/parse_lsa.c +++ b/source3/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/source3/rpc_parse/parse_net.c b/source3/rpc_parse/parse_net.c index 3bd6977dbb..e7b1cdc767 100644 --- a/source3/rpc_parse/parse_net.c +++ b/source3/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; @@ -1490,6 +1490,47 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr, /* "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")); + } + + +} + /******************************************************************* This code has been modified to cope with a NET_USER_INFO_2 - which is exactly the same as a NET_USER_INFO_3, minus the other sids parameters. @@ -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/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index 7c84ee800b..c4f9f512ab 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/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/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c index ea4ec2c863..544d139acb 100644 --- a/source3/rpc_parse/parse_rpc.c +++ b/source3/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/source3/rpc_parse/parse_samr.c b/source3/rpc_parse/parse_samr.c index 6c2b4f4ea7..7cbaa4e3c9 100644 --- a/source3/rpc_parse/parse_samr.c +++ b/source3/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/source3/rpc_server/srv_dfs.c b/source3/rpc_server/srv_dfs.c index 42be7c5a35..44a9c06a3c 100644 --- a/source3/rpc_server/srv_dfs.c +++ b/source3/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 <jmcd@us.ibm.com> 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/source3/rpc_server/srv_dfs_nt.c b/source3/rpc_server/srv_dfs_nt.c index 63e4d4e9b7..f04d8c37c3 100644 --- a/source3/rpc_server/srv_dfs_nt.c +++ b/source3/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;i<num_j;i++) { - pstring str; - dfs1[i].ptr_entrypath = 1; - slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), - j[i].service_name, j[i].volume_name); - DEBUG(5,("init_reply_dfs_info_1: %d) initing entrypath: %s\n",i,str)); - init_unistr2(&dfs1[i].entrypath,str,UNI_STR_TERMINATE); - } + pstring str; + dfs1->ptr0_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;i<num_j;i++) { - pstring str; - dfs2[i].ptr_entrypath = 1; - slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), - j[i].service_name, j[i].volume_name); - init_unistr2(&dfs2[i].entrypath, str, UNI_STR_TERMINATE); - dfs2[i].ptr_comment = 0; - dfs2[i].state = 1; /* set up state of dfs junction as OK */ - dfs2[i].num_storages = j[i].referral_count; - } + pstring str; + dfs2->ptr0_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;i<num_j;i++) { - pstring str; - dfs3[i].ptr_entrypath = 1; - if (j[i].volume_name[0] == '\0') - slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s", - global_myname(), j[i].service_name); - else - slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), - j[i].service_name, j[i].volume_name); - - init_unistr2(&dfs3[i].entrypath, str, UNI_STR_TERMINATE); - dfs3[i].ptr_comment = 1; - init_unistr2(&dfs3[i].comment, "", UNI_STR_TERMINATE); - dfs3[i].state = 1; - dfs3[i].num_storages = dfs3[i].num_storage_infos = j[i].referral_count; - dfs3[i].ptr_storages = 1; - - /* also enumerate the storages */ - dfs3[i].storages = TALLOC_ARRAY(ctx, DFS_STORAGE_INFO, j[i].referral_count); - if (!dfs3[i].storages) - return False; - - memset(dfs3[i].storages, '\0', j[i].referral_count * sizeof(DFS_STORAGE_INFO)); - - for(ii=0;ii<j[i].referral_count;ii++) { - char* p; - pstring path; - DFS_STORAGE_INFO* stor = &(dfs3[i].storages[ii]); - struct referral* ref = &(j[i].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 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;ii<j->referral_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/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index f48f3e863a..c93107cec4 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -9,6 +9,7 @@ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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; } @@ -227,87 +226,6 @@ static void init_reply_lookup_names(LSA_R_LOOKUP_NAMES *r_l, } /*************************************************************************** - 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; i<num_sids; i++) { + sids[i] = &q_u->sids.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; i<MAX_REF_DOMAINS; i++) { + + if (!dom_infos[i].valid) { + break; + } + + if (init_dom_ref(ref, dom_infos[i].name, + &dom_infos[i].sid) != i) { + DEBUG(0, ("Domain %s mentioned twice??\n", + dom_infos[i].name)); + r_u->status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + } + + for (i=0; i<num_sids; i++) { + struct lsa_name_info *name = &name_infos[i]; + + if (name->type == 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/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c index 643921f596..fd78f954cc 100644 --- a/source3/rpc_server/srv_netlog_nt.c +++ b/source3/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; i<num_sids; i++) { + DOM_GID gid; + if (!sid_peek_check_rid(domain_sid, &sids[i], &gid.g_rid)) { + continue; + } + gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT| + SE_GROUP_ENABLED); + ADD_TO_ARRAY(mem_ctx, DOM_GID, gid, pgids, numgroups); + if (*pgids == NULL) { + return NT_STATUS_NO_MEMORY; } } - *pgids = gids; return NT_STATUS_OK; } @@ -655,7 +652,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * /* 'server schannel = yes' should enforce use of schannel, the client did offer it in auth2, but obviously did not use it. */ - DEBUG(0,("_net_sam_logoff: client %s not using schannel for netlogon\n", + DEBUG(0,("_net_sam_logon: client %s not using schannel for netlogon\n", p->dc->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/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 381adbe635..68b3a2d434 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/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/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index 37d3ef64c0..86a04e7ccb 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/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/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 2f9d494a26..81344cdc1e 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/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; i<num_groups; i++) { - uint32 rid; if (!sid_peek_check_rid(get_global_sam_sid(), - &(sids[i]), &rid)) + &(sids[i]), &dom_gid.g_rid)) { + DEBUG(10, ("Found sid %s not in our domain\n", + sid_string_static(&sids[i]))); continue; + } - gids = TALLOC_REALLOC_ARRAY(p->mem_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/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index a22d6db266..e6d45f76ec 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/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/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index 8150a8bf69..f279c98c31 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/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; i<max_len && name[i]; i++ ) { - /* fail if strchr_m() finds one of the invalid characters */ - if ( name[i] && strchr_m( invalid_chars, name[i] ) ) - return False; - } - - return True; -} - /******************************************************************* Utility function to get the 'type' of a share from an snum. ********************************************************************/ @@ -132,189 +112,10 @@ static void init_srv_share_info_2(pipes_struct *p, SRV_SHARE_INFO_2 *sh2, int sn } /******************************************************************* - 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/source3/rpcclient/cmd_dfs.c b/source3/rpcclient/cmd_dfs.c index 956dbfa402..b4d43bda5e 100644 --- a/source3/rpcclient/cmd_dfs.c +++ b/source3/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/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 5adaf46981..1b7ebac45f 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/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/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c index 991b55a13c..93a3e39036 100644 --- a/source3/rpcclient/cmd_samr.c +++ b/source3/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/source3/sam/idmap.c b/source3/sam/idmap.c index 9fc1a573a9..aac8b70013 100644 --- a/source3/sam/idmap.c +++ b/source3/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) { @@ -338,23 +362,6 @@ NTSTATUS idmap_allocate_id(unid_t *id, int 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/source3/sam/idmap_ad.c b/source3/sam/idmap_ad.c index 47e349483d..f9a959e7ec 100644 --- a/source3/sam/idmap_ad.c +++ b/source3/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/source3/sam/idmap_ldap.c b/source3/sam/idmap_ldap.c index b4a8c8a752..17482a5146 100644 --- a/source3/sam/idmap_ldap.c +++ b/source3/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/source3/sam/idmap_rid.c b/source3/sam/idmap_rid.c index eced549a55..0922000fa1 100644 --- a/source3/sam/idmap_rid.c +++ b/source3/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/source3/sam/idmap_smbldap.c b/source3/sam/idmap_smbldap.c index b1aae2b86f..4d80364437 100644 --- a/source3/sam/idmap_smbldap.c +++ b/source3/sam/idmap_smbldap.c @@ -87,15 +87,6 @@ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) } /***************************************************************************** - 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/source3/sam/idmap_tdb.c b/source3/sam/idmap_tdb.c index e89a6cf547..665c56d2f6 100644 --- a/source3/sam/idmap_tdb.c +++ b/source3/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; @@ -46,41 +43,6 @@ static struct idmap_state { } 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/source3/sam/idmap_util.c b/source3/sam/idmap_util.c index cac8934f7b..7233cb48cd 100644 --- a/source3/sam/idmap_util.c +++ b/source3/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/source3/script/installman.sh b/source3/script/installman.sh index 9235217ff0..3bbca1a8aa 100755 --- a/source3/script/installman.sh +++ b/source3/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/source3/script/installswat.sh b/source3/script/installswat.sh index c66fd29485..c5c285894e 100755 --- a/source3/script/installswat.sh +++ b/source3/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/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index bb30519319..0798541cb5 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/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/source3/smbd/conn.c b/source3/smbd/conn.c index bb000bac30..bf4db99ea6 100644 --- a/source3/smbd/conn.c +++ b/source3/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/source3/smbd/lanman.c b/source3/smbd/lanman.c index 4778702e7a..83dfdf0d8b 100644 --- a/source3/smbd/lanman.c +++ b/source3/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; - - switch (uLevel) { - case 0: struct_len = 16; break; - case 1: struct_len = 26; break; - default: return -1; - } + int struct_len; + char* p; + char* p2; + int l2; + int len; - 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;i<total;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) 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;i<total;i++) { + struct srv_info_struct *s = &servers[i]; + + if (lastname && strequal(lastname,s->name)) { + 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<count;i++) { - fstring servicename_dos; - if (!(lp_browseable(i) && lp_snum_ok(i))) - continue; - push_ascii_fstring(servicename_dos, lp_servicename(i)); - if( lp_browseable( i ) - && lp_snum_ok( i ) - && (strlen(servicename_dos) < 13) ) /* Maximum name length. */ - { - total++; - data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0); - if (data_len <= buf_len) - { - counted++; - fixed_len += f_len; - string_len += s_len; - } - else - missed = True; - } - } - *rdata_len = fixed_len + string_len; - *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); - memset(*rdata,0,*rdata_len); + /* Ensure all the usershares are loaded. */ + become_root(); + count = load_usershare_shares(); + unbecome_root(); + + data_len = fixed_len = string_len = 0; + for (i=0;i<count;i++) { + fstring servicename_dos; + if (!(lp_browseable(i) && lp_snum_ok(i))) { + continue; + } + push_ascii_fstring(servicename_dos, lp_servicename(i)); + /* Maximum name length = 13. */ + if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) { + total++; + data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0); + if (data_len <= buf_len) { + counted++; + fixed_len += f_len; + string_len += s_len; + } else { + missed = True; + } + } + } + + *rdata_len = fixed_len + string_len; + *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len); + memset(*rdata,0,*rdata_len); - p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - for( i = 0; i < count; i++ ) - { - fstring servicename_dos; - if (!(lp_browseable(i) && lp_snum_ok(i))) - continue; - push_ascii_fstring(servicename_dos, lp_servicename(i)); - if( lp_browseable( i ) - && lp_snum_ok( i ) - && (strlen(servicename_dos) < 13) ) - { - if( fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0 ) - break; - } - } + p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ + p = *rdata; + f_len = fixed_len; + s_len = string_len; + + for( i = 0; i < count; i++ ) { + fstring servicename_dos; + if (!(lp_browseable(i) && lp_snum_ok(i))) { + continue; + } + + push_ascii_fstring(servicename_dos, lp_servicename(i)); + if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) { + if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) { + break; + } + } + } - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,total); + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,counted); + SSVAL(*rparam,6,total); - DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", - counted,total,uLevel, - buf_len,*rdata_len,mdrcnt)); - return(True); + DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", + counted,total,uLevel, + buf_len,*rdata_len,mdrcnt)); + + return True; } /**************************************************************************** @@ -1640,87 +1709,104 @@ static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,ch 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); - fstring sharename; - fstring comment; - pstring pathname; - char *command, *cmdname; - unsigned int offset; - int snum; - int res = ERRunsup; + 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; - - pull_ascii_fstring(sharename,data); - snum = find_service(sharename); - if (snum >= 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; + /* 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; + } + + pull_ascii_fstring(sharename,data); + snum = find_service(sharename); + if (snum >= 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; + 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; } /**************************************************************************** @@ -1744,18 +1830,21 @@ static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,c int num_entries; - if (strcmp(str1,"WrLeh") != 0) + 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) + /* 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; i<num_groups; i++) { const char *grp_name; - if ( lookup_sid(sampw->mem_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<count;i++) { - if (strequal(servers[i].name,get_local_machine_name())) { - servertype = servers[i].type; - push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE); - } - } - } - SAFE_FREE(servers); - - SCVAL(p,0,lp_major_announce_version()); - SCVAL(p,1,lp_minor_announce_version()); - SIVAL(p,2,servertype); - - if (mdrcnt == struct_len) { - SIVAL(p,6,0); - } else { - SIVAL(p,6,PTR_DIFF(p2,*rdata)); - standard_sub_conn(conn,comment,sizeof(comment)); - StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0)); - p2 = skip_string(p2,1); - } - } - if (uLevel > 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<count;i++) { + if (strequal(servers[i].name,get_local_machine_name())) { + servertype = servers[i].type; + push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE); + } + } + } + + SAFE_FREE(servers); + + SCVAL(p,0,lp_major_announce_version()); + SCVAL(p,1,lp_minor_announce_version()); + SIVAL(p,2,servertype); + + if (mdrcnt == struct_len) { + SIVAL(p,6,0); + } else { + SIVAL(p,6,PTR_DIFF(p2,*rdata)); + standard_sub_conn(conn,comment,sizeof(comment)); + StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0)); + p2 = skip_string(p2,1); + } + } + + if (uLevel > 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,77 +3172,86 @@ 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; + + 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, @@ -3116,114 +3259,137 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa 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; + 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 (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); + 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<num_sessions; i++) { - PACKS(&desc, "z", session_list[i].remote_machine); - PACKS(&desc, "z", session_list[i].username); - PACKI(&desc, "W", 1); /* num conns */ - PACKI(&desc, "W", 0); /* num opens */ - PACKI(&desc, "W", 1); /* num users */ - PACKI(&desc, "D", 0); /* session time */ - PACKI(&desc, "D", 0); /* idle time */ - PACKI(&desc, "D", 0); /* flags */ - PACKS(&desc, "z", "Unknown Client"); /* client type string */ - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); /* converter */ - SSVAL(*rparam,4,num_sessions); /* count */ - - DEBUG(4,("RNetSessionEnum: 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; + 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<num_sessions; i++) { + PACKS(&desc, "z", session_list[i].remote_machine); + PACKS(&desc, "z", session_list[i].username); + PACKI(&desc, "W", 1); /* num conns */ + PACKI(&desc, "W", 0); /* num opens */ + PACKI(&desc, "W", 1); /* num users */ + PACKI(&desc, "D", 0); /* session time */ + PACKI(&desc, "D", 0); /* idle time */ + PACKI(&desc, "D", 0); /* flags */ + PACKS(&desc, "z", "Unknown Client"); /* client type string */ + } + + *rdata_len = desc.usedlen; + + *rparam_len = 8; + *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); /* converter */ + SSVAL(*rparam,4,num_sessions); /* count */ + + DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode)); + + return True; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 1279fe185d..4f7858d985 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -1094,13 +1094,19 @@ out: int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max) { int i=0; + int sharecount = 0; int jn_count = 0; if(!lp_host_msdfs()) { return 0; } - for(i=0;i < lp_numservices() && (jn_max - jn_count) > 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/source3/smbd/ntquotas.c b/source3/smbd/ntquotas.c index 9bc444d253..a824978ece 100644 --- a/source3/smbd/ntquotas.c +++ b/source3/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/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index e12a24968b..417e3421cb 100644 --- a/source3/smbd/nttrans.c +++ b/source3/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/source3/smbd/open.c b/source3/smbd/open.c index 4b13e28f8e..4f28e291cd 100644 --- a/source3/smbd/open.c +++ b/source3/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/source3/smbd/password.c b/source3/smbd/password.c index 764fbe8a2e..e644550400 100644 --- a/source3/smbd/password.c +++ b/source3/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/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 5db245ac0c..d4dd926089 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/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/source3/smbd/process.c b/source3/smbd/process.c index 0b7b94cce2..d646ebe02d 100644 --- a/source3/smbd/process.c +++ b/source3/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/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index fc6a858974..ebc47c51d9 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/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; @@ -180,51 +180,6 @@ fail: } /**************************************************************************** - 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/source3/smbd/server.c b/source3/smbd/server.c index 3e970ec16c..6c2034988a 100644 --- a/source3/smbd/server.c +++ b/source3/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/source3/smbd/service.c b/source3/smbd/service.c index 7640559d53..cf0116cc09 100644 --- a/source3/smbd/service.c +++ b/source3/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; i<conn->nt_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/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index a22a575c76..38e16126e2 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/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/source3/smbd/share_access.c b/source3/smbd/share_access.c new file mode 100644 index 0000000000..11e52b03ab --- /dev/null +++ b/source3/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/source3/smbd/uid.c b/source3/smbd/uid.c index d419720c33..6e516d3562 100644 --- a/source3/smbd/uid.c +++ b/source3/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/source3/utils/net.c b/source3/utils/net.c index 25e10c6a31..069047c9ec 100644 --- a/source3/utils/net.c +++ b/source3/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/source3/utils/net.h b/source3/utils/net.h index 2df13cfb8f..fc3167012d 100644 --- a/source3/utils/net.h +++ b/source3/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/source3/utils/net_ads_gpo.c b/source3/utils/net_ads_gpo.c new file mode 100644 index 0000000000..fec6fb88fa --- /dev/null +++ b/source3/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 <COMMAND>\n"\ +"<COMMAND> 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/source3/utils/net_groupmap.c b/source3/utils/net_groupmap.c index 1cff120c39..96a6aa531a 100644 --- a/source3/utils/net_groupmap.c +++ b/source3/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/source3/utils/net_help.c b/source3/utils/net_help.c index c5188c3608..79062345ab 100644 --- a/source3/utils/net_help.c +++ b/source3/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 <command>\tto run ADS commands\n"\ " net rap <command>\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/source3/utils/net_lookup.c b/source3/utils/net_lookup.c index 8ee63515d4..dd2d666d5a 100644 --- a/source3/utils/net_lookup.c +++ b/source3/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 <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 <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/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 0495a7b92c..a9dc3a1fc6 100644 --- a/source3/utils/net_rpc.c +++ b/source3/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 <username>\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 <username>\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 <username> [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 <username> [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 <share> <path> [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 <share>\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 <share>\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/source3/utils/net_rpc_rights.c b/source3/utils/net_rpc_rights.c index 2c15fef5a0..2f02b40948 100644 --- a/source3/utils/net_rpc_rights.c +++ b/source3/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/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index 09e62d9def..45fdfbfad3 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/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; i<delta->num_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; i<delta->num_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; i<delta->num_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/source3/utils/net_rpc_shell.c b/source3/utils/net_rpc_shell.c new file mode 100644 index 0000000000..f9675e430b --- /dev/null +++ b/source3/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/source3/utils/net_sam.c b/source3/utils/net_sam.c new file mode 100644 index 0000000000..ba3ec5c57f --- /dev/null +++ b/source3/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 <user> <value>\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 <user> [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 <user> " + "[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 <name> " + "<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 <name>\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 <name>\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 <group> <member>\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 <group> <member>\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 <group>\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<num_members; i++) { + const char *dom, *name; + if (lookup_sid(tmp_talloc_ctx(), &members[i], + &dom, &name, NULL)) { + d_printf(" %s\\%s\n", dom, name); + } else { + d_printf(" %s\n", + sid_string_static(&members[i])); + } + } + } else { + d_fprintf(stderr, "Can only list local group members so far.\n" + "%s is a %s\n", argv[0], sid_type_lookup(grouptype)); + return -1; + } + + return 0; +} + +/* + * Do the listing + */ +static int net_sam_do_list(int argc, const char **argv, + struct pdb_search *search, const char *what) +{ + BOOL verbose = (argc == 1); + + if ((argc > 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 <name>\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/source3/utils/net_usershare.c b/source3/utils/net_usershare.c new file mode 100644 index 0000000000..c00f239b99 --- /dev/null +++ b/source3/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] <sharename> <path> [<comment>] [<acl>]\n" + "\tAdds the specified share name for this user.\n" + "\t<sharename> is the new share name.\n" + "\t<path> is the path on the filesystem to export.\n" + "\t<comment> is the optional comment for the new share.\n" + "\t<acl> 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 <sharename>\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 <sharename> <path> [<comment>] [<acl>] to add or change a user defined share.\n" + "net usershare delete <sharename> 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 <option>\" to get more information on that option\n\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +/*************************************************************************** +***************************************************************************/ + +static void get_basepath(pstring basepath) +{ + pstrcpy(basepath, lp_usershare_path()); + if (basepath[strlen(basepath)-1] == '/') { + basepath[strlen(basepath)-1] = '\0'; + } +} + +/*************************************************************************** + Delete a single userlevel share. +***************************************************************************/ + +static int net_usershare_delete(int argc, const char **argv) +{ + pstring us_path; + char *sharename; + + if (argc != 1) { + return net_usershare_delete_usage(argc, argv); + } + + sharename = strdup_lower(argv[0]); + + if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) { + d_fprintf(stderr, "net usershare delete: share name %s contains " + "invalid characters (any of %s)\n", + sharename, INVALID_SHARENAME_CHARS); + SAFE_FREE(sharename); + return -1; + } + + pstrcpy(us_path, lp_usershare_path()); + pstrcat(us_path, "/"); + pstrcat(us_path, sharename); + + if (unlink(us_path) != 0) { + d_fprintf(stderr, "net usershare delete: unable to remove usershare %s. " + "Error was %s\n", + us_path, strerror(errno)); + SAFE_FREE(sharename); + return -1; + } + SAFE_FREE(sharename); + return 0; +} + +/*************************************************************************** + Data structures to handle a list of usershare files. +***************************************************************************/ + +struct file_list { + struct file_list *next, *prev; + const char *pathname; +}; + +static struct file_list *flist; + +/*************************************************************************** +***************************************************************************/ + +static int get_share_list(TALLOC_CTX *ctx, const char *wcard, BOOL only_ours) +{ + SMB_STRUCT_DIR *dp; + SMB_STRUCT_DIRENT *de; + uid_t myuid = geteuid(); + struct file_list *fl = NULL; + pstring basepath; + + get_basepath(basepath); + dp = sys_opendir(basepath); + if (!dp) { + d_fprintf(stderr, "get_share_list: cannot open usershare directory %s. Error %s\n", + basepath, strerror(errno) ); + return -1; + } + + while((de = sys_readdir(dp)) != 0) { + SMB_STRUCT_STAT sbuf; + pstring path; + const char *n = de->d_name; + + /* Ignore . and .. */ + if (*n == '.') { + if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) { + continue; + } + } + + if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) { + d_fprintf(stderr, "get_share_list: ignoring bad share name %s\n",n); + continue; + } + pstrcpy(path, basepath); + pstrcat(path, "/"); + pstrcat(path, n); + + if (sys_lstat(path, &sbuf) != 0) { + d_fprintf(stderr, "get_share_list: can't lstat file %s. Error was %s\n", + path, strerror(errno) ); + continue; + } + + if (!S_ISREG(sbuf.st_mode)) { + d_fprintf(stderr, "get_share_list: file %s is not a regular file. Ignoring.\n", + path ); + continue; + } + + if (only_ours && sbuf.st_uid != myuid) { + continue; + } + + if (!unix_wild_match(wcard, n)) { + continue; + } + + /* (Finally) - add to list. */ + fl = TALLOC_P(ctx, struct file_list); + if (!fl) { + return -1; + } + fl->pathname = talloc_strdup(ctx, n); + if (!fl->pathname) { + return -1; + } + + DLIST_ADD(flist, fl); + } + + sys_closedir(dp); + return 0; +} + +enum priv_op { US_LIST_OP, US_INFO_OP}; + +struct priv_info { + TALLOC_CTX *ctx; + enum priv_op op; +}; + +/*************************************************************************** + Call a function for every share on the list. +***************************************************************************/ + +static int process_share_list(int (*fn)(struct file_list *, void *), void *private) +{ + struct file_list *fl; + int ret = 0; + + for (fl = flist; fl; fl = fl->next) { + ret = (*fn)(fl, private); + } + + return ret; +} + +/*************************************************************************** + Info function. +***************************************************************************/ + +static int info_fn(struct file_list *fl, void *private) +{ + SMB_STRUCT_STAT sbuf; + char **lines = NULL; + struct priv_info *pi = (struct priv_info *)private; + TALLOC_CTX *ctx = pi->ctx; + int fd = -1; + int numlines = 0; + SEC_DESC *psd = NULL; + pstring basepath; + pstring sharepath; + pstring comment; + pstring acl_str; + int num_aces; + char sep_str[2]; + enum usershare_err us_err; + + sep_str[0] = *lp_winbind_separator(); + sep_str[1] = '\0'; + + get_basepath(basepath); + pstrcat(basepath, "/"); + pstrcat(basepath, fl->pathname); + +#ifdef O_NOFOLLOW + fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0); +#else + fd = sys_open(basepath, O_RDONLY, 0); +#endif + + if (fd == -1) { + d_fprintf(stderr, "info_fn: unable to open %s. %s\n", + basepath, strerror(errno) ); + return -1; + } + + /* Paranoia... */ + if (sys_fstat(fd, &sbuf) != 0) { + d_fprintf(stderr, "info_fn: can't fstat file %s. Error was %s\n", + basepath, strerror(errno) ); + close(fd); + return -1; + } + + if (!S_ISREG(sbuf.st_mode)) { + d_fprintf(stderr, "info_fn: file %s is not a regular file. Ignoring.\n", + basepath ); + close(fd); + return -1; + } + + lines = fd_lines_load(fd, &numlines, 10240); + close(fd); + + if (lines == NULL) { + return -1; + } + + /* Ensure it's well formed. */ + us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines, + sharepath, + comment, + &psd); + + if (us_err != USERSHARE_OK) { + d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n", + basepath ); + d_fprintf(stderr, "info_fn: Error was %s.\n", + get_us_error_code(us_err) ); + return -1; + } + + pstrcpy(acl_str, "usershare_acl="); + + for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) { + char access_str[2]; + const char *domain; + const char *name; + + access_str[1] = '\0'; + + if (net_lookup_name_from_sid(ctx, &psd->dacl->ace[num_aces].trustee, &domain, &name)) { + if (*domain) { + pstrcat(acl_str, domain); + pstrcat(acl_str, sep_str); + } + pstrcat(acl_str,name); + } else { + fstring sidstr; + sid_to_string(sidstr, &psd->dacl->ace[num_aces].trustee); + pstrcat(acl_str,sidstr); + } + pstrcat(acl_str, ":"); + + if (psd->dacl->ace[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) { + pstrcat(acl_str, "D,"); + } else { + if (psd->dacl->ace[num_aces].info.mask & GENERIC_ALL_ACCESS) { + pstrcat(acl_str, "F,"); + } else { + pstrcat(acl_str, "R,"); + } + } + } + + acl_str[strlen(acl_str)-1] = '\0'; + + if (pi->op == US_INFO_OP) { + d_printf("[%s]\n", fl->pathname ); + d_printf("path=%s\n", sharepath ); + d_printf("comment=%s\n", comment); + d_printf("%s\n\n", acl_str); + } else if (pi->op == US_LIST_OP) { + d_printf("%s\n", fl->pathname); + } + + return 0; +} + +/*************************************************************************** + Print out info (internal detail) on userlevel shares. +***************************************************************************/ + +static int net_usershare_info(int argc, const char **argv) +{ + fstring wcard; + BOOL only_ours = True; + int ret = -1; + struct priv_info pi; + TALLOC_CTX *ctx; + + fstrcpy(wcard, "*"); + + if (opt_long_list_entries) { + only_ours = False; + } + + switch (argc) { + case 0: + break; + case 1: + fstrcpy(wcard, argv[0]); + break; + default: + return net_usershare_info_usage(argc, argv); + } + + strlower_m(wcard); + + ctx = talloc_init("share_info"); + ret = get_share_list(ctx, wcard, only_ours); + if (ret) { + return ret; + } + + pi.ctx = ctx; + pi.op = US_INFO_OP; + + ret = process_share_list(info_fn, &pi); + talloc_destroy(ctx); + return ret; +} + +/*************************************************************************** + Add a single userlevel share. +***************************************************************************/ + +static int net_usershare_add(int argc, const char **argv) +{ + TALLOC_CTX *ctx = NULL; + SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT lsbuf; + char *sharename; + pstring full_path; + pstring full_path_tmp; + const char *us_path; + const char *us_comment; + const char *arg_acl; + char *us_acl; + char *file_img; + int num_aces = 0; + int i; + int tmpfd; + const char *pacl; + size_t to_write; + uid_t myeuid = geteuid(); + + us_comment = ""; + arg_acl = "S-1-1-0:R"; + + switch (argc) { + case 0: + case 1: + default: + return net_usershare_add_usage(argc, argv); + case 2: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + break; + case 3: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + us_comment = argv[2]; + break; + case 4: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + us_comment = argv[2]; + arg_acl = argv[3]; + break; + } + + if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) { + d_fprintf(stderr, "net usershare add: share name %s contains " + "invalid characters (any of %s)\n", + sharename, INVALID_SHARENAME_CHARS); + SAFE_FREE(sharename); + return -1; + } + + /* Disallow shares the same as users. */ + if (getpwnam(sharename)) { + d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n", + sharename ); + SAFE_FREE(sharename); + return -1; + } + + /* Construct the full path for the usershare file. */ + get_basepath(full_path); + pstrcat(full_path, "/"); + pstrcpy(full_path_tmp, full_path); + pstrcat(full_path, sharename); + pstrcat(full_path_tmp, ":tmpXXXXXX"); + + /* The path *must* be absolute. */ + if (us_path[0] != '/') { + d_fprintf(stderr,"net usershare add: path %s is not an absolute path.\n", + us_path); + SAFE_FREE(sharename); + return -1; + } + + /* Check the directory to be shared exists. */ + if (sys_stat(us_path, &sbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot stat path %s to ensure " + "this is a directory. Error was %s\n", + us_path, strerror(errno) ); + SAFE_FREE(sharename); + return -1; + } + + if (!S_ISDIR(sbuf.st_mode)) { + d_fprintf(stderr, "net usershare add: path %s is not a directory.\n", + us_path ); + SAFE_FREE(sharename); + return -1; + } + + /* If we're not root, check if we're restricted to sharing out directories + that we own only. */ + + if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_uid)) { + d_fprintf(stderr, "net usershare add: cannot share path %s as " + "we are restricted to only sharing directories we own.\n", + us_path ); + SAFE_FREE(sharename); + return -1; + } + + /* No validation needed on comment. Now go through and validate the + acl string. Convert names to SID's as needed. Then run it through + parse_usershare_acl to ensure it's valid. */ + + ctx = talloc_init("share_info"); + + /* Start off the string we'll append to. */ + us_acl = talloc_strdup(ctx, ""); + + pacl = arg_acl; + num_aces = 1; + + /* Add the number of ',' characters to get the number of aces. */ + num_aces += count_chars(pacl,','); + + for (i = 0; i < num_aces; i++) { + DOM_SID sid; + const char *pcolon = strchr_m(pacl, ':'); + const char *name; + + if (pcolon == NULL) { + d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + switch(pcolon[1]) { + case 'f': + case 'F': + case 'd': + case 'r': + case 'R': + break; + default: + d_fprintf(stderr, "net usershare add: malformed acl %s " + "(access control must be 'r', 'f', or 'd')\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (pcolon[2] != ',' && pcolon[2] != '\0') { + d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Get the name */ + name = talloc_strndup(ctx, pacl, pcolon - pacl); + if (!string_to_sid(&sid, name)) { + /* Convert to a SID */ + if (!net_lookup_sid_from_name(ctx, name, &sid)) { + d_fprintf(stderr, "net usershare add: cannot convert name %s to a SID.\n", + name ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + } + us_acl = talloc_asprintf_append(us_acl, "%s:%c,", sid_string_static(&sid), pcolon[1]); + + /* Move to the next ACL entry. */ + if (pcolon[2] == ',') { + pacl = &pcolon[3]; + } + } + + /* Remove the last ',' */ + us_acl[strlen(us_acl)-1] = '\0'; + + /* Create a temporary filename for this share. */ + tmpfd = smb_mkstemp(full_path_tmp); + + if (tmpfd == -1) { + d_fprintf(stderr, "net usershare add: cannot create tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Ensure we opened the file we thought we did. */ + if (sys_lstat(full_path_tmp, &lsbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot lstat tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Check this is the same as the file we opened. */ + if (sys_fstat(tmpfd, &sbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot fstat tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (!S_ISREG(sbuf.st_mode) || sbuf.st_dev != lsbuf.st_dev || sbuf.st_ino != lsbuf.st_ino) { + d_fprintf(stderr, "net usershare add: tmp file %s is not a regular file ?\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (fchmod(tmpfd, 0644) == -1) { + d_fprintf(stderr, "net usershare add: failed to fchmod tmp file %s to 0644n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Create the in-memory image of the file. */ + file_img = talloc_strdup(ctx, "#VERSION 1\npath="); + file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\n", + us_path, us_comment, us_acl ); + + to_write = strlen(file_img); + + if (write(tmpfd, file_img, to_write) != to_write) { + d_fprintf(stderr, "net usershare add: failed to write %u bytes to file %s. Error was %s\n", + (unsigned int)to_write, full_path_tmp, strerror(errno)); + unlink(full_path_tmp); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Attempt to replace any existing share by this name. */ + if (rename(full_path_tmp, full_path) != 0) { + unlink(full_path_tmp); + d_fprintf(stderr, "net usershare add: failed to add share %s. Error was %s\n", + sharename, strerror(errno)); + talloc_destroy(ctx); + close(tmpfd); + SAFE_FREE(sharename); + return -1; + } + + close(tmpfd); + talloc_destroy(ctx); + + if (opt_long_list_entries) { + const char *my_argv[2]; + my_argv[0] = sharename; + my_argv[1] = NULL; + net_usershare_info(1, argv); + } + + SAFE_FREE(sharename); + return 0; +} + +#if 0 +/*************************************************************************** + List function. +***************************************************************************/ + +static int list_fn(struct file_list *fl, void *private) +{ + d_printf("%s\n", fl->pathname); + return 0; +} +#endif + +/*************************************************************************** + List userlevel shares. +***************************************************************************/ + +static int net_usershare_list(int argc, const char **argv) +{ + fstring wcard; + BOOL only_ours = True; + int ret = -1; + struct priv_info pi; + TALLOC_CTX *ctx; + + fstrcpy(wcard, "*"); + + if (opt_long_list_entries) { + only_ours = False; + } + + switch (argc) { + case 0: + break; + case 1: + fstrcpy(wcard, argv[0]); + break; + default: + return net_usershare_list_usage(argc, argv); + } + + strlower_m(wcard); + + ctx = talloc_init("share_list"); + ret = get_share_list(ctx, wcard, only_ours); + if (ret) { + return ret; + } + + pi.ctx = ctx; + pi.op = US_LIST_OP; + + ret = process_share_list(info_fn, &pi); + talloc_destroy(ctx); + return ret; +} + +/*************************************************************************** + Handle "net usershare help *" subcommands. +***************************************************************************/ + +int net_usershare_help(int argc, const char **argv) +{ + struct functable func[] = { + {"ADD", net_usershare_add_usage}, + {"DELETE", net_usershare_delete_usage}, + {"INFO", net_usershare_info_usage}, + {"LIST", net_usershare_list_usage}, + {NULL, NULL}}; + + return net_run_function(argc, argv, func, net_usershare_usage); +} + +/*************************************************************************** + Entry-point for all the USERSHARE functions. +***************************************************************************/ + +int net_usershare(int argc, const char **argv) +{ + SMB_STRUCT_DIR *dp; + + struct functable func[] = { + {"ADD", net_usershare_add}, + {"DELETE", net_usershare_delete}, + {"INFO", net_usershare_info}, + {"LIST", net_usershare_list}, + {"HELP", net_usershare_help}, + {NULL, NULL} + }; + + if (lp_usershare_max_shares() == 0) { + d_fprintf(stderr, "net usershare: usershares are currently disabled\n"); + return -1; + } + + dp = sys_opendir(lp_usershare_path()); + if (!dp) { + int err = errno; + d_fprintf(stderr, "net usershare: cannot open usershare directory %s. Error %s\n", + lp_usershare_path(), strerror(err) ); + if (err == EACCES) { + d_fprintf(stderr, "You do not have permission to create a usershare. Ask your " + "administrator to grant you permissions to create a share.\n"); + } else if (err == ENOENT) { + d_fprintf(stderr, "Please ask your system administrator to " + "enable user sharing.\n"); + } + return -1; + } + sys_closedir(dp); + + return net_run_function(argc, argv, func, net_usershare_usage); +} diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c new file mode 100644 index 0000000000..805104cefa --- /dev/null +++ b/source3/utils/net_util.c @@ -0,0 +1,89 @@ +/* + * Unix SMB/CIFS implementation. + * Helper routines for net + * 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" + +BOOL is_valid_policy_hnd(const POLICY_HND *hnd) +{ + POLICY_HND tmp; + ZERO_STRUCT(tmp); + return (memcmp(&tmp, hnd, sizeof(tmp)) != 0); +} + +NTSTATUS net_rpc_lookup_name(TALLOC_CTX *mem_ctx, struct cli_state *cli, + const char *name, const char **ret_domain, + const char **ret_name, DOM_SID *ret_sid, + enum SID_NAME_USE *ret_type) +{ + struct rpc_pipe_client *lsa_pipe; + POLICY_HND pol; + NTSTATUS result = NT_STATUS_OK; + const char **dom_names; + DOM_SID *sids; + uint32_t *types; + + ZERO_STRUCT(pol); + + lsa_pipe = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &result); + if (lsa_pipe == NULL) { + 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)) { + d_fprintf(stderr, "open_policy failed: %s\n", + nt_errstr(result)); + return result; + } + + result = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1, + &name, &dom_names, &sids, &types); + + if (!NT_STATUS_IS_OK(result)) { + /* This can happen easily, don't log an error */ + goto done; + } + + if (ret_domain != NULL) { + *ret_domain = dom_names[0]; + } + if (ret_name != NULL) { + *ret_name = talloc_strdup(mem_ctx, name); + } + if (ret_sid != NULL) { + sid_copy(ret_sid, &sids[0]); + } + if (ret_type != NULL) { + *ret_type = types[0]; + } + + done: + if (is_valid_policy_hnd(&pol)) { + rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); + } + cli_rpc_pipe_close(lsa_pipe); + + return result; +} diff --git a/source3/utils/netlookup.c b/source3/utils/netlookup.c new file mode 100644 index 0000000000..edb2f7d5ba --- /dev/null +++ b/source3/utils/netlookup.c @@ -0,0 +1,209 @@ +/* + Unix SMB/CIFS implementation. + + Name lookup. + + 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. +*/ + +#include "includes.h" +#include "utils/net.h" + +/******************************************************** + Connection cachine struct. Goes away when ctx destroyed. +********************************************************/ + +struct con_struct { + BOOL failed_connect; + struct cli_state *cli; + struct rpc_pipe_client *lsapipe; + POLICY_HND pol; +}; + +static struct con_struct *cs; + +/******************************************************** + Close connection on context destruction. +********************************************************/ + +static int cs_destructor(void *p) +{ + if (cs->cli) { + cli_shutdown(cs->cli); + } + cs = NULL; + return 0; +} + +/******************************************************** + Create the connection to localhost. +********************************************************/ + +static struct con_struct *create_cs(TALLOC_CTX *ctx) +{ + NTSTATUS nt_status; + struct in_addr loopback_ip = *interpret_addr2("127.0.0.1");; + + if (cs) { + if (cs->failed_connect) { + return NULL; + } + return cs; + } + + cs = TALLOC_P(ctx, struct con_struct); + if (!cs) { + return NULL; + } + + ZERO_STRUCTP(cs); + talloc_set_destructor(cs, cs_destructor); + + /* Connect to localhost with given username/password. */ + /* JRA. Pretty sure we can just do this anonymously.... */ +#if 0 + if (!opt_password && !opt_machine_pass) { + char *pass = getpass("Password:"); + if (pass) { + opt_password = SMB_STRDUP(pass); + } + } +#endif + + nt_status = cli_full_connection(&cs->cli, global_myname(), global_myname(), + &loopback_ip, 0, + "IPC$", "IPC", +#if 0 + opt_user_name, + opt_workgroup, + opt_password, +#else + "", + opt_workgroup, + "", +#endif + 0, + Undefined, + NULL); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("create_cs: Connect failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + cs->lsapipe = cli_rpc_pipe_open_noauth(cs->cli, + PI_LSARPC, + &nt_status); + + if (cs->lsapipe == NULL) { + DEBUG(2,("create_cs: open LSA pipe failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + nt_status = rpccli_lsa_open_policy(cs->lsapipe, ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &cs->pol); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("create_cs: rpccli_lsa_open_policy failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + return cs; +} + +/******************************************************** + Do a lookup_sids call to localhost. + Check if the local machine is authoritative for this sid. We can't + check if this is our SID as that's stored in the root-read-only + secrets.tdb. + The local smbd will also ask winbindd for us, so we don't have to. +********************************************************/ + +BOOL net_lookup_name_from_sid(TALLOC_CTX *ctx, + DOM_SID *psid, + const char **ppdomain, + const char **ppname) +{ + NTSTATUS nt_status; + struct con_struct *csp = NULL; + char **domains; + char **names; + uint32 *types; + + *ppdomain = NULL; + *ppname = NULL; + + csp = create_cs(ctx); + if (csp == NULL) { + return False; + } + + nt_status = rpccli_lsa_lookup_sids(csp->lsapipe, ctx, + &csp->pol, + 1, psid, + &domains, + &names, + &types); + + if (!NT_STATUS_IS_OK(nt_status)) { + return False; + } + + *ppdomain = domains[0]; + *ppname = names[0]; + /* Don't care about type here. */ + + /* Converted OK */ + return True; +} + +/******************************************************** + Do a lookup_names call to localhost. +********************************************************/ + +BOOL net_lookup_sid_from_name(TALLOC_CTX *ctx, const char *full_name, DOM_SID *pret_sid) +{ + NTSTATUS nt_status; + struct con_struct *csp = NULL; + DOM_SID *sids = NULL; + uint32 *types = NULL; + + csp = create_cs(ctx); + if (csp == NULL) { + return False; + } + + nt_status = rpccli_lsa_lookup_names(csp->lsapipe, ctx, + &csp->pol, + 1, + &full_name, + NULL, &sids, + &types); + + if (!NT_STATUS_IS_OK(nt_status)) { + return False; + } + + *pret_sid = sids[0]; + + /* Converted OK */ + return True; +} diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 4759aec0cc..c22f4b5e09 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1173,7 +1173,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) spnego.negTokenInit.mechListMIC.length); principal[spnego.negTokenInit.mechListMIC.length] = '\0'; - retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL); if (retval) { @@ -1191,12 +1191,12 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) pstr_sprintf(user, "%s@%s", opt_username, opt_domain); if ((retval = kerberos_kinit_password(user, opt_password, - 0, NULL, NULL))) { + 0, NULL, NULL, NULL, False, 0))) { DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval))); return False; } - retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL); if (retval) { DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval))); diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index f41bbb8caa..0b17d50ad3 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -337,7 +337,7 @@ static int fix_users_list (struct pdb_context *in) while (check && NT_STATUS_IS_OK(in->pdb_getsampwent (in, sam_pwent))) { printf("Updating record for user %s\n", pdb_get_username(sam_pwent)); - if (!pdb_update_sam_account(sam_pwent)) { + if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) { printf("Update of user %s failed!\n", pdb_get_username(sam_pwent)); } pdb_free_sam(&sam_pwent); @@ -498,7 +498,7 @@ static int new_user (struct pdb_context *in, const char *username, get_global_sam_sid(); - if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pwent, username, 0))) { + if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pwent, username))) { DEBUG(0, ("could not create account to add new user %s\n", username)); return -1; } @@ -603,13 +603,13 @@ static int new_machine (struct pdb_context *in, const char *machine_in) fstrcpy(machineaccount, machinename); fstrcat(machineaccount, "$"); - if ((pwd = getpwnam_alloc(machineaccount))) { + if ((pwd = getpwnam_alloc(NULL, machineaccount))) { if (!NT_STATUS_IS_OK(pdb_init_sam_pw( &sam_pwent, pwd))) { fprintf(stderr, "Could not init sam from pw\n"); - passwd_free(&pwd); + talloc_free(pwd); return -1; } - passwd_free(&pwd); + talloc_free(&pwd); } else { if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) { fprintf(stderr, "Could not init sam from pw\n"); diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 26362c6270..cff3bc5dde 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -145,7 +145,7 @@ static BOOL StringToSid(DOM_SID *sid, const char *str) if (!cacls_open_policy_hnd() || !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, global_hack_cli->mem_ctx, - &pol, 1, &str, &sids, + &pol, 1, &str, NULL, &sids, &types))) { result = False; goto done; diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index a4d2766b13..405e51cd25 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -584,6 +584,107 @@ static BOOL do_drvupgrade(const struct process_id pid, pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); } +static BOOL do_winbind_online(const struct process_id pid, + const int argc, const char **argv) +{ + TDB_CONTEXT *tdb; + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd online\n"); + return False; + } + + if (!lp_winbind_offline_logon()) { + fprintf(stderr, "The parameter \"winbind offline logon\" must " + "be set in the [global] section of smb.conf for this " + "command to be allowed.\n"); + return False; + } + + /* Remove the entry in the winbindd_cache tdb to tell a later + starting winbindd that we're online. */ + + tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); + if (!tdb) { + fprintf(stderr, "Cannot open the tdb %s for writing.\n", + lock_path("winbindd_cache.tdb")); + return False; + } + + tdb_delete_bystring(tdb, "WINBINDD_OFFLINE"); + tdb_close(tdb); + + return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False); +} + +static BOOL do_winbind_offline(const struct process_id pid, + const int argc, const char **argv) +{ + TDB_CONTEXT *tdb; + BOOL ret = False; + int retry = 0; + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd offline\n"); + return False; + } + + if (!lp_winbind_offline_logon()) { + fprintf(stderr, "The parameter \"winbind offline logon\" must " + "be set in the [global] section of smb.conf for this " + "command to be allowed.\n"); + return False; + } + + /* Create an entry in the winbindd_cache tdb to tell a later + starting winbindd that we're offline. We may actually create + it here... */ + + 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 (!tdb) { + fprintf(stderr, "Cannot open the tdb %s for writing.\n", + lock_path("winbindd_cache.tdb")); + return False; + } + + /* There's a potential race condition that if a child + winbindd detects a domain is online at the same time + we're trying to tell it to go offline that it might + delete the record we add between us adding it and + sending the message. Minimize this by retrying up to + 5 times. */ + + for (retry = 0; retry < 5; retry++) { + int err; + TDB_DATA d; + ZERO_STRUCT(d); + tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT); + + ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False); + + /* Check that the entry "WINBINDD_OFFLINE" still exists. */ + tdb->ecode = 0; + d = tdb_fetch_bystring( 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(tdb); + + if (err == TDB_ERR_NOEXIST) { + DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n")); + } else { + break; + } + } + + tdb_close(tdb); + return ret; +} + static BOOL do_reload_config(const struct process_id pid, const int argc, const char **argv) { @@ -668,6 +769,8 @@ static const struct { { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"}, { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"}, + { "online", do_winbind_online, "Ask winbind to go into online state"}, + { "offline", do_winbind_offline, "Ask winbind to go into offline state"}, { "noop", do_noop, "Do nothing" }, { NULL } }; @@ -681,7 +784,7 @@ static void usage(poptContext *pc) poptPrintHelp(*pc, stderr, 0); fprintf(stderr, "\n"); - fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a " + fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a " "process ID\n"); fprintf(stderr, "\n"); @@ -715,10 +818,17 @@ static struct process_id parse_dest(const char *dest) return pid_to_procid(sys_getpid()); } + /* Fix winbind typo. */ + if (strequal(dest, "winbind")) { + dest = "winbindd"; + } + /* Check for numeric pid number */ result = interpret_pid(dest); - if (procid_valid(&result)) { + + /* Zero isn't valid if not smbd. */ + if (result.pid && procid_valid(&result)) { return result; } diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c index b1a14685f5..7b3268e783 100644 --- a/source3/utils/smbcquotas.c +++ b/source3/utils/smbcquotas.c @@ -116,7 +116,7 @@ static BOOL StringToSid(DOM_SID *sid, const char *str) if (!cli_open_policy_hnd() || !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, cli_ipc->mem_ctx, - &pol, 1, &str, &sids, + &pol, 1, &str, NULL, &sids, &types))) { result = False; goto done; diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index 7eb11137d7..4323ee29e0 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -270,10 +270,11 @@ static char *prompt_for_new_password(BOOL stdin_get) Change a password either locally or remotely. *************************************************************/ -static BOOL password_change(const char *remote_mach, char *username, - char *old_passwd, char *new_pw, int local_flags) +static NTSTATUS password_change(const char *remote_mach, char *username, + char *old_passwd, char *new_pw, + int local_flags) { - BOOL ret; + NTSTATUS ret; pstring err_str; pstring msg_str; @@ -281,7 +282,7 @@ static BOOL password_change(const char *remote_mach, char *username, if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER| LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) { /* these things can't be done remotely yet */ - return False; + return NT_STATUS_UNSUCCESSFUL; } ret = remote_password_change(remote_mach, username, old_passwd, new_pw, err_str, sizeof(err_str)); @@ -370,9 +371,9 @@ static int process_root(int local_flags) load_interfaces(); } - if (!user_name[0] && (pwd = getpwuid_alloc(geteuid()))) { + if (!user_name[0] && (pwd = getpwuid_alloc(NULL, geteuid()))) { fstrcpy(user_name, pwd->pw_name); - passwd_free(&pwd); + talloc_free(pwd); } if (!user_name[0]) { @@ -465,7 +466,9 @@ static int process_root(int local_flags) } } - if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) { + if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, + old_passwd, new_passwd, + local_flags))) { fprintf(stderr,"Failed to modify password entry for user %s\n", user_name); result = 1; goto done; @@ -512,10 +515,10 @@ static int process_nonroot(int local_flags) } if (!user_name[0]) { - pwd = getpwuid_alloc(getuid()); + pwd = getpwuid_alloc(NULL, getuid()); if (pwd) { fstrcpy(user_name,pwd->pw_name); - passwd_free(&pwd); + talloc_free(pwd); } else { fprintf(stderr, "smbpasswd: cannot lookup user name for uid %u\n", (unsigned int)getuid()); exit(1); @@ -549,7 +552,8 @@ static int process_nonroot(int local_flags) exit(1); } - if (!password_change(remote_machine, user_name, old_pw, new_pw, 0)) { + if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw, + new_pw, 0))) { fprintf(stderr,"Failed to change password for %s\n", user_name); result = 1; goto done; diff --git a/source3/web/cgi.c b/source3/web/cgi.c index 6c9cfce13c..700fb7fa08 100644 --- a/source3/web/cgi.c +++ b/source3/web/cgi.c @@ -293,7 +293,7 @@ static void cgi_web_auth(void) exit(0); } - pwd = getpwnam_alloc(user); + pwd = getpwnam_alloc(NULL, user); if (!pwd) { printf("%sCannot find user %s<br>%s\n", head, user, tail); exit(0); @@ -306,7 +306,7 @@ static void cgi_web_auth(void) head, user, (int)geteuid(), (int)getuid(), tail); exit(0); } - passwd_free(&pwd); + talloc_free(pwd); } @@ -346,7 +346,7 @@ static BOOL cgi_handle_authorization(char *line) * Try and get the user from the UNIX password file. */ - pass = getpwnam_alloc(user); + pass = getpwnam_alloc(NULL, user); /* * Validate the password they have given. @@ -367,7 +367,7 @@ static BOOL cgi_handle_authorization(char *line) /* Save the users name */ C_user = SMB_STRDUP(user); - passwd_free(&pass); + talloc_free(pass); return True; } } @@ -377,7 +377,7 @@ err: "WWW-Authenticate: Basic realm=\"SWAT\"\r\n", "username or password incorrect"); - passwd_free(&pass); + talloc_free(pass); return False; } diff --git a/source3/web/swat.c b/source3/web/swat.c index 63253e41c4..af01d1f31b 100644 --- a/source3/web/swat.c +++ b/source3/web/swat.c @@ -982,7 +982,7 @@ static BOOL change_password(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, int local_flags) { - BOOL ret = False; + NTSTATUS ret; pstring err_str; pstring msg_str; @@ -996,7 +996,7 @@ static BOOL change_password(const char *remote_machine, const char *user_name, new_passwd, err_str, sizeof(err_str)); if(*err_str) printf("%s\n<p>", err_str); - return ret; + return NT_STATUS_IS_OK(ret); } if(!initialize_password_db(True)) { @@ -1012,7 +1012,7 @@ static BOOL change_password(const char *remote_machine, const char *user_name, if(*err_str) printf("%s\n<p>", err_str); - return ret; + return NT_STATUS_IS_OK(ret); } /**************************************************************************** |