1/* 2 * Unix SMB/CIFS implementation. 3 * RPC Pipe client / server routines for Dfs 4 * Copyright (C) Andrew Tridgell 1992-1997, 5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, 6 * Copyright (C) Shirish Kalele 2000. 7 * Copyright (C) Jeremy Allison 2001. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24/* This is the implementation of the dfs pipe. */ 25 26#include "includes.h" 27#include "nterr.h" 28 29#undef DBGC_CLASS 30#define DBGC_CLASS DBGC_RPC_SRV 31 32#define MAX_MSDFS_JUNCTIONS 256 33 34/* This function does not return a WERROR or NTSTATUS code but rather 1 if 35 dfs exists, or 0 otherwise. */ 36 37uint32 _dfs_exist(pipes_struct *p, DFS_Q_DFS_EXIST *q_u, DFS_R_DFS_EXIST *r_u) 38{ 39 if(lp_host_msdfs()) 40 return 1; 41 else 42 return 0; 43} 44 45WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u) 46{ 47 struct current_user user; 48 struct junction_map jn; 49 struct referral* old_referral_list = NULL; 50 BOOL exists = False; 51 52 pstring dfspath, servername, sharename; 53 pstring altpath; 54 55 get_current_user(&user,p); 56 57 if (user.uid != 0) { 58 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n")); 59 return WERR_ACCESS_DENIED; 60 } 61 62 unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1); 63 unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1); 64 unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1); 65 66 DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n", 67 dfspath, servername, sharename)); 68 69 pstrcpy(altpath, servername); 70 pstrcat(altpath, "\\"); 71 pstrcat(altpath, sharename); 72 73 /* The following call can change the cwd. */ 74 if(get_referred_path(dfspath, &jn, NULL, NULL)) { 75 exists = True; 76 jn.referral_count += 1; 77 old_referral_list = jn.referral_list; 78 } else { 79 jn.referral_count = 1; 80 } 81 82 vfs_ChDir(p->conn,p->conn->connectpath); 83 84 jn.referral_list = TALLOC_ARRAY(p->mem_ctx, struct referral, jn.referral_count); 85 if(jn.referral_list == NULL) { 86 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n")); 87 return WERR_DFS_INTERNAL_ERROR; 88 } 89 90 if(old_referral_list) { 91 memcpy(jn.referral_list, old_referral_list, sizeof(struct referral)*jn.referral_count-1); 92 SAFE_FREE(old_referral_list); 93 } 94 95 jn.referral_list[jn.referral_count-1].proximity = 0; 96 jn.referral_list[jn.referral_count-1].ttl = REFERRAL_TTL; 97 98 pstrcpy(jn.referral_list[jn.referral_count-1].alternate_path, altpath); 99 100 if(!create_msdfs_link(&jn, exists)) { 101 vfs_ChDir(p->conn,p->conn->connectpath); 102 return WERR_DFS_CANT_CREATE_JUNCT; 103 } 104 vfs_ChDir(p->conn,p->conn->connectpath); 105 106 return WERR_OK; 107} 108 109WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u, 110 DFS_R_DFS_REMOVE *r_u) 111{ 112 struct current_user user; 113 struct junction_map jn; 114 BOOL found = False; 115 116 pstring dfspath, servername, sharename; 117 pstring altpath; 118 119 get_current_user(&user,p); 120 121 if (user.uid != 0) { 122 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n")); 123 return WERR_ACCESS_DENIED; 124 } 125 126 unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1); 127 if(q_u->ptr_ServerName) { 128 unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1); 129 } 130 131 if(q_u->ptr_ShareName) { 132 unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1); 133 } 134 135 if(q_u->ptr_ServerName && q_u->ptr_ShareName) { 136 pstrcpy(altpath, servername); 137 pstrcat(altpath, "\\"); 138 pstrcat(altpath, sharename); 139 strlower_m(altpath); 140 } 141 142 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n", 143 dfspath, servername, sharename)); 144 145 if(!get_referred_path(dfspath, &jn, NULL, NULL)) { 146 return WERR_DFS_NO_SUCH_VOL; 147 } 148 149 /* if no server-share pair given, remove the msdfs link completely */ 150 if(!q_u->ptr_ServerName && !q_u->ptr_ShareName) { 151 if(!remove_msdfs_link(&jn)) { 152 vfs_ChDir(p->conn,p->conn->connectpath); 153 return WERR_DFS_NO_SUCH_VOL; 154 } 155 vfs_ChDir(p->conn,p->conn->connectpath); 156 } else { 157 int i=0; 158 /* compare each referral in the list with the one to remove */ 159 DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath, jn.referral_count)); 160 for(i=0;i<jn.referral_count;i++) { 161 pstring refpath; 162 pstrcpy(refpath,jn.referral_list[i].alternate_path); 163 trim_char(refpath, '\\', '\\'); 164 DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath)); 165 if(strequal(refpath, altpath)) { 166 *(jn.referral_list[i].alternate_path)='\0'; 167 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n", 168 refpath)); 169 found = True; 170 } 171 } 172 173 if(!found) { 174 return WERR_DFS_NO_SUCH_SHARE; 175 } 176 177 /* Only one referral, remove it */ 178 if(jn.referral_count == 1) { 179 if(!remove_msdfs_link(&jn)) { 180 vfs_ChDir(p->conn,p->conn->connectpath); 181 return WERR_DFS_NO_SUCH_VOL; 182 } 183 } else { 184 if(!create_msdfs_link(&jn, True)) { 185 vfs_ChDir(p->conn,p->conn->connectpath); 186 return WERR_DFS_CANT_CREATE_JUNCT; 187 } 188 } 189 vfs_ChDir(p->conn,p->conn->connectpath); 190 } 191 192 return WERR_OK; 193} 194 195static BOOL init_reply_dfs_info_1(struct junction_map* j, DFS_INFO_1* dfs1, int num_j) 196{ 197 int i=0; 198 for(i=0;i<num_j;i++) { 199 pstring str; 200 dfs1[i].ptr_entrypath = 1; 201 slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), 202 j[i].service_name, j[i].volume_name); 203 DEBUG(5,("init_reply_dfs_info_1: %d) initing entrypath: %s\n",i,str)); 204 init_unistr2(&dfs1[i].entrypath,str,UNI_STR_TERMINATE); 205 } 206 return True; 207} 208 209static BOOL init_reply_dfs_info_2(struct junction_map* j, DFS_INFO_2* dfs2, int num_j) 210{ 211 int i=0; 212 for(i=0;i<num_j;i++) { 213 pstring str; 214 dfs2[i].ptr_entrypath = 1; 215 slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), 216 j[i].service_name, j[i].volume_name); 217 init_unistr2(&dfs2[i].entrypath, str, UNI_STR_TERMINATE); 218 dfs2[i].ptr_comment = 0; 219 dfs2[i].state = 1; /* set up state of dfs junction as OK */ 220 dfs2[i].num_storages = j[i].referral_count; 221 } 222 return True; 223} 224 225static BOOL init_reply_dfs_info_3(TALLOC_CTX *ctx, struct junction_map* j, DFS_INFO_3* dfs3, int num_j) 226{ 227 int i=0,ii=0; 228 for(i=0;i<num_j;i++) { 229 pstring str; 230 dfs3[i].ptr_entrypath = 1; 231 if (j[i].volume_name[0] == '\0') 232 slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s", 233 global_myname(), j[i].service_name); 234 else 235 slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname(), 236 j[i].service_name, j[i].volume_name); 237 238 init_unistr2(&dfs3[i].entrypath, str, UNI_STR_TERMINATE); 239 dfs3[i].ptr_comment = 1; 240 init_unistr2(&dfs3[i].comment, "", UNI_STR_TERMINATE); 241 dfs3[i].state = 1; 242 dfs3[i].num_storages = dfs3[i].num_storage_infos = j[i].referral_count; 243 dfs3[i].ptr_storages = 1; 244 245 /* also enumerate the storages */ 246 dfs3[i].storages = TALLOC_ARRAY(ctx, DFS_STORAGE_INFO, j[i].referral_count); 247 if (!dfs3[i].storages) 248 return False; 249 250 memset(dfs3[i].storages, '\0', j[i].referral_count * sizeof(DFS_STORAGE_INFO)); 251 252 for(ii=0;ii<j[i].referral_count;ii++) { 253 char* p; 254 pstring path; 255 DFS_STORAGE_INFO* stor = &(dfs3[i].storages[ii]); 256 struct referral* ref = &(j[i].referral_list[ii]); 257 258 pstrcpy(path, ref->alternate_path); 259 trim_char(path,'\\','\0'); 260 p = strrchr_m(path,'\\'); 261 if(p==NULL) { 262 DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path)); 263 continue; 264 } 265 *p = '\0'; 266 DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1)); 267 stor->state = 2; /* set all storages as ONLINE */ 268 init_unistr2(&stor->servername, path, UNI_STR_TERMINATE); 269 init_unistr2(&stor->sharename, p+1, UNI_STR_TERMINATE); 270 stor->ptr_servername = stor->ptr_sharename = 1; 271 } 272 } 273 return True; 274} 275 276static WERROR init_reply_dfs_ctr(TALLOC_CTX *ctx, uint32 level, 277 DFS_INFO_CTR* ctr, struct junction_map* jn, 278 int num_jn) 279{ 280 /* do the levels */ 281 switch(level) { 282 case 1: 283 { 284 DFS_INFO_1* dfs1; 285 dfs1 = TALLOC_ARRAY(ctx, DFS_INFO_1, num_jn); 286 if (!dfs1) 287 return WERR_NOMEM; 288 init_reply_dfs_info_1(jn, dfs1, num_jn); 289 ctr->dfs.info1 = dfs1; 290 break; 291 } 292 case 2: 293 { 294 DFS_INFO_2* dfs2; 295 dfs2 = TALLOC_ARRAY(ctx, DFS_INFO_2, num_jn); 296 if (!dfs2) 297 return WERR_NOMEM; 298 init_reply_dfs_info_2(jn, dfs2, num_jn); 299 ctr->dfs.info2 = dfs2; 300 break; 301 } 302 case 3: 303 { 304 DFS_INFO_3* dfs3; 305 dfs3 = TALLOC_ARRAY(ctx, DFS_INFO_3, num_jn); 306 if (!dfs3) 307 return WERR_NOMEM; 308 init_reply_dfs_info_3(ctx, jn, dfs3, num_jn); 309 ctr->dfs.info3 = dfs3; 310 break; 311 } 312 default: 313 return WERR_INVALID_PARAM; 314 } 315 return WERR_OK; 316} 317 318WERROR _dfs_enum(pipes_struct *p, DFS_Q_DFS_ENUM *q_u, DFS_R_DFS_ENUM *r_u) 319{ 320 uint32 level = q_u->level; 321 struct junction_map jn[MAX_MSDFS_JUNCTIONS]; 322 int num_jn = 0; 323 324 num_jn = enum_msdfs_links(jn); 325 vfs_ChDir(p->conn,p->conn->connectpath); 326 327 DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n", num_jn, level)); 328 329 r_u->ptr_buffer = level; 330 r_u->level = r_u->level2 = level; 331 r_u->ptr_num_entries = r_u->ptr_num_entries2 = 1; 332 r_u->num_entries = r_u->num_entries2 = num_jn; 333 r_u->reshnd.ptr_hnd = 1; 334 r_u->reshnd.handle = num_jn; 335 336 r_u->ctr = TALLOC_P(p->mem_ctx, DFS_INFO_CTR); 337 if (!r_u->ctr) 338 return WERR_NOMEM; 339 ZERO_STRUCTP(r_u->ctr); 340 r_u->ctr->switch_value = level; 341 r_u->ctr->num_entries = num_jn; 342 r_u->ctr->ptr_dfs_ctr = 1; 343 344 r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, r_u->ctr, jn, num_jn); 345 346 return r_u->status; 347} 348 349WERROR _dfs_get_info(pipes_struct *p, DFS_Q_DFS_GET_INFO *q_u, 350 DFS_R_DFS_GET_INFO *r_u) 351{ 352 UNISTR2* uni_path = &q_u->uni_path; 353 uint32 level = q_u->level; 354 int consumedcnt = sizeof(pstring); 355 pstring path; 356 struct junction_map jn; 357 358 unistr2_to_ascii(path, uni_path, sizeof(path)-1); 359 if(!create_junction(path, &jn)) 360 return WERR_DFS_NO_SUCH_SERVER; 361 362 /* The following call can change the cwd. */ 363 if(!get_referred_path(path, &jn, &consumedcnt, NULL) || consumedcnt < strlen(path)) { 364 vfs_ChDir(p->conn,p->conn->connectpath); 365 return WERR_DFS_NO_SUCH_VOL; 366 } 367 368 vfs_ChDir(p->conn,p->conn->connectpath); 369 r_u->level = level; 370 r_u->ptr_ctr = 1; 371 r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, &r_u->ctr, &jn, 1); 372 373 return r_u->status; 374} 375