X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fservice.c;h=8039d16586eb164f576f4c4def3a919aac6feff1;hb=bd269443e311d96ef495a9db47d1b95eb83bb8f4;hp=30e48018e9a6449e71d90f63b072776364a53ada;hpb=d2157f13422da4991ffcc007c7bc3c07e1f42912;p=samba.git diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 30e48018e9a..8039d16586e 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -18,6 +18,7 @@ */ #include "includes.h" +#include "smbd/globals.h" extern userdom_struct current_user_info; @@ -55,7 +56,12 @@ bool set_conn_connectpath(connection_struct *conn, const char *connectpath) const char *s = connectpath; bool start_of_name_component = true; - destname = SMB_STRDUP(connectpath); + if (connectpath == NULL || connectpath[0] == '\0') { + return false; + } + + /* Allocate for strlen + '\0' + possible leading '/' */ + destname = SMB_MALLOC(strlen(connectpath) + 2); if (!destname) { return false; } @@ -167,8 +173,6 @@ bool set_conn_connectpath(connection_struct *conn, const char *connectpath) bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir) { - static connection_struct *last_conn; - static uint16 last_flags; int snum; if (!conn) { @@ -183,8 +187,8 @@ bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir) if (do_chdir && vfs_ChDir(conn,conn->connectpath) != 0 && vfs_ChDir(conn,conn->origpath) != 0) { - DEBUG(0,("chdir (%s) failed\n", - conn->connectpath)); + DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n", + conn->connectpath, strerror(errno))); return(False); } @@ -221,97 +225,34 @@ bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir) static int load_registry_service(const char *servicename) { - struct registry_key *key; - char *path; - WERROR err; - - uint32 i; - char *value_name; - struct registry_value *value; - - int res = -1; - if (!lp_registry_shares()) { return -1; } - if (strequal(servicename, GLOBAL_NAME)) { - return -2; - } - - if (asprintf(&path, "%s\\%s", KEY_SMBCONF, servicename) == -1) { + if ((servicename == NULL) || (*servicename == '\0')) { return -1; } - err = reg_open_path(NULL, path, REG_KEY_READ, get_root_nt_token(), - &key); - SAFE_FREE(path); - - if (!W_ERROR_IS_OK(err)) { - return -1; - } - - res = lp_add_service(servicename, -1); - if (res == -1) { - goto error; + if (strequal(servicename, GLOBAL_NAME)) { + return -2; } - for (i=0; - W_ERROR_IS_OK(reg_enumvalue(key, key, i, &value_name, &value)); - i++) { - switch (value->type) { - case REG_DWORD: { - char *tmp; - if (asprintf(&tmp, "%d", value->v.dword) == -1) { - continue; - } - lp_do_parameter(res, value_name, tmp); - SAFE_FREE(tmp); - break; - } - case REG_SZ: { - lp_do_parameter(res, value_name, value->v.sz.str); - break; - } - default: - /* Ignore all the rest */ - break; - } - - TALLOC_FREE(value_name); - TALLOC_FREE(value); + if (!process_registry_service(servicename)) { + return -1; } - error: - - TALLOC_FREE(key); - return res; + return lp_servicenumber(servicename); } void load_registry_shares(void) { - struct registry_key *key; - char *name; - WERROR err; - int i; - DEBUG(8, ("load_registry_shares()\n")); if (!lp_registry_shares()) { return; } - err = reg_open_path(NULL, KEY_SMBCONF, REG_KEY_READ, - get_root_nt_token(), &key); - if (!(W_ERROR_IS_OK(err))) { - return; - } - - for (i=0; W_ERROR_IS_OK(reg_enumkey(key, key, i, &name, NULL)); i++) { - load_registry_service(name); - TALLOC_FREE(name); - } + process_registry_shares(); - TALLOC_FREE(key); return; } @@ -323,7 +264,7 @@ int add_home_service(const char *service, const char *username, const char *home { int iHomeService; - if (!service || !homedir) + if (!service || !homedir || homedir[0] == '\0') return -1; if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) { @@ -365,6 +306,7 @@ int add_home_service(const char *service, const char *username, const char *home int find_service(fstring service) { int iService; + struct smbd_server_connection *sconn = smbd_server_conn; all_string_sub(service,"\\","/",0); @@ -379,7 +321,7 @@ int find_service(fstring service) * Try mapping the servicename, it may * be a Windows to unix mapped user name. */ - if(map_username(service)) + if(map_username(sconn, service)) phome_dir = get_user_home_dir( talloc_tos(), service); } @@ -620,7 +562,8 @@ static NTSTATUS find_forced_group(bool force_user, Create an auth_serversupplied_info structure for a connection_struct ****************************************************************************/ -static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, +static NTSTATUS create_connection_server_info(struct smbd_server_connection *sconn, + TALLOC_CTX *mem_ctx, int snum, struct auth_serversupplied_info *vuid_serverinfo, DATA_BLOB password, struct auth_serversupplied_info **presult) @@ -646,6 +589,7 @@ static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, } } else { if (!user_ok_token(vuid_serverinfo->unix_name, + pdb_get_domain(vuid_serverinfo->sam_account), vuid_serverinfo->ptok, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " @@ -673,11 +617,11 @@ static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, /* add the sharename as a possible user name if we are in share mode security */ - add_session_user(lp_servicename(snum)); + add_session_user(sconn, lp_servicename(snum)); /* shall we let them in? */ - if (!authorise_login(snum,user,password,&guest)) { + if (!authorise_login(sconn, snum,user,password,&guest)) { DEBUG( 2, ( "Invalid username/password for [%s]\n", lp_servicename(snum)) ); return NT_STATUS_WRONG_PASSWORD; @@ -697,13 +641,14 @@ static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, connecting user if appropriate. ****************************************************************************/ -static connection_struct *make_connection_snum(int snum, user_struct *vuser, - DATA_BLOB password, - const char *pdev, - NTSTATUS *pstatus) +connection_struct *make_connection_snum(struct smbd_server_connection *sconn, + int snum, user_struct *vuser, + DATA_BLOB password, + const char *pdev, + NTSTATUS *pstatus) { connection_struct *conn; - SMB_STRUCT_STAT st; + struct smb_filename *smb_fname_cpath = NULL; fstring dev; int ret; char addr[INET6_ADDRSTRLEN]; @@ -711,13 +656,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, NTSTATUS status; fstrcpy(dev, pdev); - SET_STAT_INVALID(st); if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) { return NULL; } - conn = conn_new(); + conn = conn_new(sconn); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; @@ -725,14 +669,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, } conn->params->service = snum; - conn->nt_user_token = NULL; - status = create_connection_server_info( + status = create_connection_server_info(sconn, conn, snum, vuser ? vuser->server_info : NULL, password, &conn->server_info); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("create_connection_server_info failed: %s\n", + DEBUG(1, ("create_connection_server_info failed: %s\n", nt_errstr(status))); *pstatus = status; conn_free(conn); @@ -743,8 +686,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->force_user = true; } - - add_session_user(conn->server_info->unix_name); + add_session_user(sconn, conn->server_info->unix_name); safe_strcpy(conn->client_address, client_addr(get_client_fd(),addr,sizeof(addr)), @@ -755,7 +697,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) ); - conn->dirptr = NULL; /* Case options for the share. */ if (lp_casesensitive(snum) == Auto) { @@ -775,18 +716,17 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->hide_list = NULL; conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; - string_set(&conn->dirpath,""); conn->read_only = lp_readonly(SNUM(conn)); conn->admin_user = False; - /* - * 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)) { + + /* + * Replace conn->server_info with a completely faked up one + * from the username we are forced into :-) + */ + char *fuser; struct auth_serversupplied_info *forced_serverinfo; @@ -814,92 +754,43 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, DEBUG(3,("Forced user %s\n", fuser)); } - conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID; - - conn->uid = conn->server_info->uid; - conn->gid = conn->server_info->gid; - string_set(&conn->user, conn->server_info->unix_name); - /* * If force group is true, then override * any groupid stored for the connecting user. */ - + if (*lp_force_group(snum)) { - DOM_SID group_sid; - status = find_forced_group(conn->force_user, snum, - conn->user, - &group_sid, &conn->gid); + status = find_forced_group( + conn->force_user, snum, conn->server_info->unix_name, + &conn->server_info->ptok->user_sids[1], + &conn->server_info->utok.gid); + if (!NT_STATUS_IS_OK(status)) { conn_free(conn); *pstatus = status; return NULL; } - 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->server_info->ptok); - if (conn->nt_user_token == NULL) { - DEBUG(0, ("dup_nt_token failed\n")); - conn_free(conn); - *pstatus = NT_STATUS_NO_MEMORY; - return NULL; - } - } - - /* 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); - - } + /* + * We need to cache this gid, to use within + * change_to_user() separately from the conn->server_info + * struct. We only use conn->server_info directly if + * "force_user" was set. + */ + conn->force_group_gid = conn->server_info->utok.gid; } - if (conn->nt_user_token != NULL) { - size_t i; - - /* We have a share-specific token from force [user|group]. - * This means we have to create the list of unix groups from - * the list of sids. */ - - conn->ngroups = 0; - conn->groups = NULL; - - for (i=0; int_user_token->num_sids; i++) { - gid_t gid; - DOM_SID *sid = &conn->nt_user_token->user_sids[i]; - - if (!sid_to_gid(sid, &gid)) { - DEBUG(10, ("Could not convert SID %s to gid, " - "ignoring it\n", - sid_string_dbg(sid))); - continue; - } - if (!add_gid_to_array_unique(conn, gid, &conn->groups, - &conn->ngroups)) { - DEBUG(0, ("add_gid_to_array_unique failed\n")); - conn_free(conn); - *pstatus = NT_STATUS_NO_MEMORY; - return NULL; - } - } - } + conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID; { char *s = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), conn->user, - conn->connectpath, conn->gid, - get_current_username(), - current_user_info.domain, + lp_servicename(SNUM(conn)), + conn->server_info->unix_name, + conn->connectpath, + conn->server_info->utok.gid, + conn->server_info->sanitized_username, + pdb_get_domain(conn->server_info->sam_account), lp_pathname(snum)); if (!s) { conn_free(conn); @@ -927,32 +818,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, { bool can_write = False; - NT_USER_TOKEN *token = conn->nt_user_token ? - conn->nt_user_token : - (vuser ? vuser->server_info->ptok : NULL); - /* - * I don't believe this can happen. But the - * logic above is convoluted enough to confuse - * automated checkers, so be sure. JRA. - */ - - if (token == NULL) { - DEBUG(0,("make_connection: connection to %s " - "denied due to missing " - "NT token.\n", - lp_servicename(snum))); - conn_free(conn); - *pstatus = NT_STATUS_ACCESS_DENIED; - return NULL; - } - - can_write = share_access_check(token, - lp_servicename(snum), - FILE_WRITE_DATA); + can_write = share_access_check(conn->server_info->ptok, + lp_servicename(snum), + FILE_WRITE_DATA); if (!can_write) { - if (!share_access_check(token, + if (!share_access_check(conn->server_info->ptok, lp_servicename(snum), FILE_READ_DATA)) { /* No access, read or write. */ @@ -1035,10 +907,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* execute any "root preexec = " line */ if (*lp_rootpreexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), conn->user, - conn->connectpath, conn->gid, - get_current_username(), - current_user_info.domain, + lp_servicename(SNUM(conn)), + conn->server_info->unix_name, + conn->connectpath, + conn->server_info->utok.gid, + conn->server_info->sanitized_username, + pdb_get_domain(conn->server_info->sam_account), lp_rootpreexec(snum)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); @@ -1072,10 +946,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* execute any "preexec = " line */ if (*lp_preexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), conn->user, - conn->connectpath, conn->gid, - get_current_username(), - current_user_info.domain, + lp_servicename(SNUM(conn)), + conn->server_info->unix_name, + conn->connectpath, + conn->server_info->utok.gid, + conn->server_info->sanitized_username, + pdb_get_domain(conn->server_info->sam_account), lp_preexec(snum)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); @@ -1098,13 +974,16 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, set_namearray( &conn->veto_list, lp_veto_files(snum)); set_namearray( &conn->hide_list, lp_hide_files(snum)); set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum)); + set_namearray( &conn->aio_write_behind_list, + lp_aio_write_behind(snum)); } /* Invoke VFS make connection hook - do this before the VFS_STAT call to allow any filesystems needing user credentials to initialize themselves. */ - if (SMB_VFS_CONNECT(conn, lp_servicename(snum), conn->user) < 0) { + if (SMB_VFS_CONNECT(conn, lp_servicename(snum), + conn->server_info->unix_name) < 0) { DEBUG(0,("make_connection: VFS make connection failed!\n")); *pstatus = NT_STATUS_UNSUCCESSFUL; goto err_root_exit; @@ -1113,14 +992,21 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* Any error exit after here needs to call the disconnect hook. */ on_err_call_dis_hook = true; + status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath, + NULL, NULL, &smb_fname_cpath); + if (!NT_STATUS_IS_OK(status)) { + *pstatus = status; + goto err_root_exit; + } + /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ - if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 || - !S_ISDIR(st.st_mode)) { - if (ret == 0 && !S_ISDIR(st.st_mode)) { + if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || + !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { + if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(snum))); @@ -1153,12 +1039,20 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, } #endif + if (lp_unix_extensions() && lp_widelinks(snum)) { + DEBUG(0,("Share '%s' has wide links and unix extensions enabled. " + "These parameters are incompatible. " + "Disabling wide links for this share.\n", + lp_servicename(snum) )); + lp_do_parameter(snum, "wide links", "False"); + } + /* Figure out the characteristics of the underlying filesystem. This * assumes that all the filesystem mounted withing a share path have * the same characteristics, which is likely but not guaranteed. */ - conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn); + conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Print out the 'connected as' stuff here as we need @@ -1169,9 +1063,10 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); - dbgtext( "%s", srv_is_signing_active() ? "signed " : ""); + dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(snum) ); - dbgtext( "initially as user %s ", conn->user ); + dbgtext( "initially as user %s ", + conn->server_info->unix_name ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); dbgtext( "(pid %d)\n", (int)sys_getpid() ); } @@ -1181,7 +1076,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return(conn); err_root_exit: - + TALLOC_FREE(smb_fname_cpath); change_to_root_user(); if (on_err_call_dis_hook) { /* Call VFS disconnect hook */ @@ -1192,45 +1087,14 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } -/*************************************************************************************** - Simple wrapper function for make_connection() to include a call to - vfs_chdir() - **************************************************************************************/ - -connection_struct *make_connection_with_chdir(const char *service_in, - DATA_BLOB password, - const char *dev, uint16 vuid, - NTSTATUS *status) -{ - connection_struct *conn = NULL; - - conn = make_connection(service_in, password, dev, vuid, status); - - /* - * make_connection() does not change the directory for us any more - * so we have to do it as a separate step --jerry - */ - - if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { - DEBUG(0,("move_driver_to_download_area: Can't change " - "directory to %s for [print$] (%s)\n", - conn->connectpath,strerror(errno))); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } - - return conn; -} - /**************************************************************************** Make a connection to a service. * * @param service ****************************************************************************/ -connection_struct *make_connection(const char *service_in, DATA_BLOB password, +connection_struct *make_connection(struct smbd_server_connection *sconn, + const char *service_in, DATA_BLOB password, const char *pdev, uint16 vuid, NTSTATUS *status) { @@ -1251,13 +1115,13 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); } - if (conn_num_open() > 2047) { + if (conn_num_open(sconn) > 2047) { *status = NT_STATUS_INSUFF_SERVER_RESOURCES; return NULL; } if(lp_security() != SEC_SHARE) { - vuser = get_valid_user_struct(vuid); + vuser = get_valid_user_struct(sconn, vuid); if (!vuser) { DEBUG(1,("make_connection: refusing to connect with " "no session setup\n")); @@ -1288,7 +1152,8 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, } DEBUG(5, ("making a connection to [homes] service " "created at session setup time\n")); - return make_connection_snum(vuser->homes_snum, + return make_connection_snum(sconn, + vuser->homes_snum, vuser, no_pw, dev, status); } else { @@ -1298,14 +1163,15 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, fstring unix_username; fstrcpy(unix_username, current_user_info.smb_name); - map_username(unix_username); + map_username(sconn, unix_username); snum = find_service(unix_username); } if (snum != -1) { DEBUG(5, ("making a connection to 'homes' " "service %s based on " "security=share\n", service_in)); - return make_connection_snum(snum, NULL, + return make_connection_snum(sconn, + snum, NULL, password, dev, status); } @@ -1316,7 +1182,8 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, DATA_BLOB no_pw = data_blob_null; DEBUG(5, ("making a connection to 'homes' service [%s] " "created at session setup time\n", service_in)); - return make_connection_snum(vuser->homes_snum, + return make_connection_snum(sconn, + vuser->homes_snum, vuser, no_pw, dev, status); } @@ -1335,7 +1202,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, return NULL; } - DEBUG(0,("%s (%s) couldn't find service %s\n", + DEBUG(3,("%s (%s) couldn't find service %s\n", get_remote_machine_name(), client_addr(get_client_fd(),addr,sizeof(addr)), service)); @@ -1354,7 +1221,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, DEBUG(5, ("making a connection to 'normal' service %s\n", service)); - return make_connection_snum(snum, vuser, + return make_connection_snum(sconn, snum, vuser, password, dev, status); } @@ -1365,10 +1232,9 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, void close_cnum(connection_struct *conn, uint16 vuid) { - if (IS_IPC(conn)) { - pipe_close_conn(conn); - } else { - file_close_conn(conn); + file_close_conn(conn); + + if (!IS_IPC(conn)) { dptr_closecnum(conn); } @@ -1391,10 +1257,12 @@ void close_cnum(connection_struct *conn, uint16 vuid) if (*lp_postexec(SNUM(conn)) && change_to_user(conn, vuid)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), conn->user, - conn->connectpath, conn->gid, - get_current_username(), - current_user_info.domain, + lp_servicename(SNUM(conn)), + conn->server_info->unix_name, + conn->connectpath, + conn->server_info->utok.gid, + conn->server_info->sanitized_username, + pdb_get_domain(conn->server_info->sam_account), lp_postexec(SNUM(conn))); smbrun(cmd,NULL); TALLOC_FREE(cmd); @@ -1405,10 +1273,12 @@ void close_cnum(connection_struct *conn, uint16 vuid) /* execute any "root postexec = " line */ if (*lp_rootpostexec(SNUM(conn))) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), conn->user, - conn->connectpath, conn->gid, - get_current_username(), - current_user_info.domain, + lp_servicename(SNUM(conn)), + conn->server_info->unix_name, + conn->connectpath, + conn->server_info->utok.gid, + conn->server_info->sanitized_username, + pdb_get_domain(conn->server_info->sam_account), lp_rootpostexec(SNUM(conn))); smbrun(cmd,NULL); TALLOC_FREE(cmd);