get rid of compiler warnings (casts and delete unused variables)
[Samba/gebeck_regimport.git] / source3 / msdfs / msdfs.c
blobf2915606e839b35401fc7b962663a848fee16633
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDfs services for Samba
5 Copyright (C) Shirish Kalele 2000
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 extern pstring global_myname;
26 /**********************************************************************
27 Create a tcon relative path from a dfs_path structure
28 **********************************************************************/
30 static void create_nondfs_path(char* pathname, struct dfs_path* pdp)
32 pstrcpy(pathname,pdp->volumename);
33 pstrcat(pathname,"\\");
34 pstrcat(pathname,pdp->restofthepath);
37 /**********************************************************************
38 Parse the pathname of the form \hostname\service\volume\restofthepath
39 into the dfs_path structure
40 **********************************************************************/
42 static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
44 pstring pathname_local;
45 char* p,*temp;
47 pstrcpy(pathname_local,pathname);
48 p = temp = pathname_local;
50 ZERO_STRUCTP(pdp);
52 trim_string(temp,"\\","\\");
53 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
55 /* now tokenize */
56 /* parse out hostname */
57 p = strchr_m(temp,'\\');
58 if(p == NULL)
59 return False;
60 *p = '\0';
61 pstrcpy(pdp->hostname,temp);
62 DEBUG(10,("hostname: %s\n",pdp->hostname));
64 /* parse out servicename */
65 temp = p+1;
66 p = strchr_m(temp,'\\');
67 if(p == NULL) {
68 pstrcpy(pdp->servicename,temp);
69 return True;
71 *p = '\0';
72 pstrcpy(pdp->servicename,temp);
73 DEBUG(10,("servicename: %s\n",pdp->servicename));
75 /* parse out volumename */
76 temp = p+1;
77 p = strchr_m(temp,'\\');
78 if(p == NULL) {
79 pstrcpy(pdp->volumename,temp);
80 return True;
82 *p = '\0';
83 pstrcpy(pdp->volumename,temp);
84 DEBUG(10,("volumename: %s\n",pdp->volumename));
86 /* remaining path .. */
87 pstrcpy(pdp->restofthepath,p+1);
88 DEBUG(10,("rest of the path: %s\n",pdp->restofthepath));
89 return True;
92 /********************************************************
93 Fake up a connection struct for the VFS layer.
94 *********************************************************/
96 static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
98 ZERO_STRUCTP(conn);
99 conn->service = snum;
100 conn->connectpath = path;
102 if (!smbd_vfs_init(conn)) {
103 DEBUG(0,("create_conn_struct: vfs init failed.\n"));
104 return False;
106 return True;
109 /**********************************************************************
110 Forms a valid Unix pathname from the junction
111 **********************************************************************/
113 static BOOL form_path_from_junction(struct junction_map* jn, char* path, int max_pathlen,
114 connection_struct *conn)
116 int snum;
118 if(!path || !jn)
119 return False;
121 snum = lp_servicenumber(jn->service_name);
122 if(snum < 0)
123 return False;
125 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
126 safe_strcat(path, "/", max_pathlen-1);
127 strlower(jn->volume_name);
128 safe_strcat(path, jn->volume_name, max_pathlen-1);
130 if (!create_conn_struct(conn, snum, path))
131 return False;
133 return True;
136 /**********************************************************************
137 Creates a junction structure from the Dfs pathname
138 **********************************************************************/
140 BOOL create_junction(char* pathname, struct junction_map* jn)
142 struct dfs_path dp;
144 parse_dfs_path(pathname,&dp);
146 /* check if path is dfs : check hostname is the first token */
147 if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0)) {
148 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n", dp.hostname, pathname));
149 return False;
152 /* Check for a non-DFS share */
153 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
154 DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
155 return False;
158 pstrcpy(jn->service_name,dp.servicename);
159 pstrcpy(jn->volume_name,dp.volumename);
160 return True;
163 /**********************************************************************
164 Parse the contents of a symlink to verify if it is an msdfs referral
165 A valid referral is of the form: msdfs:server1\share1,server2\share2
166 **********************************************************************/
168 static BOOL parse_symlink(char* buf,struct referral** preflist, int* refcount)
170 pstring temp;
171 char* prot;
172 char* alt_path[MAX_REFERRAL_COUNT];
173 int count=0, i;
174 struct referral* reflist;
176 pstrcpy(temp,buf);
178 prot = strtok(temp,":");
180 if(!strequal(prot, "msdfs"))
181 return False;
183 /* It's an msdfs referral */
184 if(!preflist)
185 return True;
187 /* parse out the alternate paths */
188 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
189 count++;
191 DEBUG(10,("parse_symlink: count=%d\n", count));
193 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
194 if(reflist == NULL) {
195 DEBUG(0,("parse_symlink: Malloc failed!\n"));
196 return False;
199 for(i=0;i<count;i++) {
200 /* replace / in the alternate path by a \ */
201 char* p = strchr_m(alt_path[i],'/');
202 if(p)
203 *p = '\\';
205 pstrcpy(reflist[i].alternate_path, "\\");
206 pstrcat(reflist[i].alternate_path, alt_path[i]);
207 reflist[i].proximity = 0;
208 reflist[i].ttl = REFERRAL_TTL;
209 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
212 if(refcount)
213 *refcount = count;
215 return True;
218 /**********************************************************************
219 Returns true if the unix path is a valid msdfs symlink
220 **********************************************************************/
222 BOOL is_msdfs_link(connection_struct* conn, char* path)
224 SMB_STRUCT_STAT st;
225 pstring referral;
226 int referral_len = 0;
228 if(!path || !conn)
229 return False;
231 strlower(path);
233 if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
234 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
235 return False;
238 if(S_ISLNK(st.st_mode)) {
239 /* open the link and read it */
240 referral_len = conn->vfs_ops.readlink(conn, path, referral, sizeof(pstring));
241 if(referral_len == -1)
242 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
244 referral[referral_len] = '\0';
245 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
246 if(parse_symlink(referral, NULL, NULL))
247 return True;
249 return False;
252 /**********************************************************************
253 Fills in the junction_map struct with the referrals from the
254 symbolic link
255 **********************************************************************/
257 BOOL get_referred_path(struct junction_map* junction)
259 pstring path;
260 pstring buf;
261 SMB_STRUCT_STAT st;
262 connection_struct conns;
263 connection_struct *conn = &conns;
265 if(!form_path_from_junction(junction, path, sizeof(path), conn))
266 return False;
268 DEBUG(5,("get_referred_path: lstat target: %s\n", path));
270 if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
271 DEBUG(5,("get_referred_path: %s does not exist.\n",path));
272 return False;
275 if(S_ISLNK(st.st_mode)) {
276 /* open the link and read it to get the dfs referral */
277 int linkcnt = 0;
278 linkcnt = conn->vfs_ops.readlink(conn, path, buf, sizeof(buf));
279 buf[linkcnt] = '\0';
280 DEBUG(5,("get_referred_path: Referral: %s\n",buf));
281 if(parse_symlink(buf, &junction->referral_list, &junction->referral_count))
282 return True;
284 return False;
287 /**************************************************************
288 Decides if given pathname is Dfs and if it should be redirected
289 Converts pathname to non-dfs format if Dfs redirection not required
290 **************************************************************/
292 BOOL dfs_redirect(char* pathname, connection_struct* conn)
294 struct dfs_path dp;
295 pstring temp;
296 fstring path;
298 pstrcpy(temp,pathname);
300 if(!lp_msdfs_root(SNUM(conn)) )
301 return False;
303 parse_dfs_path(pathname,&dp);
305 if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0))
306 return False;
308 /* check if need to redirect */
309 fstrcpy(path, conn->connectpath);
310 fstrcat(path, "/");
311 fstrcat(path, dp.volumename);
312 if(is_msdfs_link(conn, path)) {
313 DEBUG(4,("dfs_redirect: Redirecting %s\n",temp));
314 return True;
315 } else {
316 create_nondfs_path(pathname,&dp);
317 DEBUG(4,("dfs_redirect: Not redirecting %s. Converted to non-dfs pathname \'%s\'\n",
318 temp,pathname));
319 return False;
324 Special DFS redirect call for findfirst's.
325 If the findfirst is for the dfs junction, then no redirection,
326 if it is for the underlying directory contents, redirect.
329 BOOL dfs_findfirst_redirect(char* pathname, connection_struct* conn)
331 struct dfs_path dp;
333 pstring temp;
335 pstrcpy(temp,pathname);
337 /* Is the path Dfs-redirectable? */
338 if(!dfs_redirect(temp,conn)) {
339 pstrcpy(pathname,temp);
340 return False;
343 parse_dfs_path(pathname,&dp);
344 DEBUG(8,("dfs_findfirst_redirect: path %s is in Dfs. dp.restofthepath=.%s.\n",
345 pathname,dp.restofthepath));
346 if(!(*(dp.restofthepath))) {
347 create_nondfs_path(pathname,&dp);
348 return False;
351 return True;
354 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
355 struct junction_map* junction,
356 BOOL self_referral)
358 char* pdata = *ppdata;
360 unsigned char uni_requestedpath[1024];
361 int uni_reqpathoffset1,uni_reqpathoffset2;
362 int uni_curroffset;
363 int requestedpathlen=0;
364 int offset;
365 int reply_size = 0;
366 int i=0;
368 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
370 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
371 STR_TERMINATE);
373 dump_data(10,(const char *)uni_requestedpath,requestedpathlen);
375 DEBUG(10,("ref count = %u\n",junction->referral_count));
377 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
378 VERSION2_REFERRAL_SIZE * junction->referral_count;
380 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
382 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
384 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
385 2 * requestedpathlen;
386 DEBUG(10,("reply_size: %u\n",reply_size));
388 /* add up the unicode lengths of all the referral paths */
389 for(i=0;i<junction->referral_count;i++) {
390 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
391 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
394 DEBUG(10,("reply_size = %u\n",reply_size));
395 /* add the unexplained 0x16 bytes */
396 reply_size += 0x16;
398 pdata = Realloc(pdata,reply_size);
399 if(pdata == NULL) {
400 DEBUG(0,("malloc failed for Realloc!\n"));
401 return -1;
403 else *ppdata = pdata;
405 /* copy in the dfs requested paths.. required for offset calculations */
406 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
407 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
409 /* create the header */
410 SSVAL(pdata,0,requestedpathlen-2); /* path consumed */
411 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
412 if(self_referral)
413 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
414 else
415 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
417 offset = 8;
418 /* add the referral elements */
419 for(i=0;i<junction->referral_count;i++) {
420 struct referral* ref = &(junction->referral_list[i]);
421 int unilen;
423 SSVAL(pdata,offset,2); /* version 2 */
424 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
425 if(self_referral)
426 SSVAL(pdata,offset+4,1);
427 else
428 SSVAL(pdata,offset+4,0);
429 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
430 SIVAL(pdata,offset+8,ref->proximity);
431 SIVAL(pdata,offset+12,ref->ttl);
433 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
434 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
435 /* copy referred path into current offset */
436 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
437 -1, STR_UNICODE);
438 SSVAL(pdata,offset+20,uni_curroffset-offset);
440 uni_curroffset += unilen;
441 offset += VERSION2_REFERRAL_SIZE;
443 /* add in the unexplained 22 (0x16) bytes at the end */
444 memset(pdata+uni_curroffset,'\0',0x16);
445 SAFE_FREE(junction->referral_list);
446 return reply_size;
449 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
450 struct junction_map* junction,
451 BOOL self_referral)
453 char* pdata = *ppdata;
455 unsigned char uni_reqpath[1024];
456 int uni_reqpathoffset1, uni_reqpathoffset2;
457 int uni_curroffset;
458 int reply_size = 0;
460 int reqpathlen = 0;
461 int offset,i=0;
463 DEBUG(10,("setting up version3 referral\n"));
465 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
467 dump_data(10,(const char *)uni_reqpath,reqpathlen);
469 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
470 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
471 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
473 for(i=0;i<junction->referral_count;i++) {
474 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
475 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
478 pdata = Realloc(pdata,reply_size);
479 if(pdata == NULL) {
480 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
481 return -1;
483 else *ppdata = pdata;
485 /* create the header */
486 SSVAL(pdata,0,reqpathlen-2); /* path consumed */
487 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
488 if(self_referral)
489 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
490 else
491 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
493 /* copy in the reqpaths */
494 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
495 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
497 offset = 8;
498 for(i=0;i<junction->referral_count;i++) {
499 struct referral* ref = &(junction->referral_list[i]);
500 int unilen;
502 SSVAL(pdata,offset,3); /* version 3 */
503 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
504 if(self_referral)
505 SSVAL(pdata,offset+4,1);
506 else
507 SSVAL(pdata,offset+4,0);
509 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
510 SIVAL(pdata,offset+8,ref->ttl);
512 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
513 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
514 /* copy referred path into current offset */
516 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
517 -1, STR_UNICODE|STR_TERMINATE);
518 SSVAL(pdata,offset+16,uni_curroffset-offset);
519 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
520 memset(pdata+offset+18,'\0',16);
522 uni_curroffset += unilen;
523 offset += VERSION3_REFERRAL_SIZE;
525 SAFE_FREE(junction->referral_list);
526 return reply_size;
529 /******************************************************************
530 * Set up the Dfs referral for the dfs pathname
531 ******************************************************************/
533 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
535 struct junction_map junction;
537 BOOL self_referral;
539 int reply_size = 0;
541 ZERO_STRUCT(junction);
543 if(!create_junction(pathname, &junction))
544 return -1;
546 /* get the junction entry */
547 if(!get_referred_path(&junction)) {
549 /* refer the same pathname, create a standard referral struct */
550 struct referral* ref;
551 self_referral = True;
552 junction.referral_count = 1;
553 if((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
554 DEBUG(0,("malloc failed for referral\n"));
555 return -1;
558 pstrcpy(ref->alternate_path,pathname);
559 ref->proximity = 0;
560 ref->ttl = REFERRAL_TTL;
561 junction.referral_list = ref;
562 } else {
563 self_referral = False;
564 if( DEBUGLVL( 3 ) ) {
565 int i=0;
566 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathname);
567 for(i=0;i<junction.referral_count;i++)
568 dbgtext(" %s",junction.referral_list[i].alternate_path);
569 dbgtext(".\n");
573 /* create the referral depeding on version */
574 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
575 if(max_referral_level<2 || max_referral_level>3)
576 max_referral_level = 2;
578 switch(max_referral_level) {
579 case 2:
581 reply_size = setup_ver2_dfs_referral(pathname, ppdata, &junction, self_referral);
582 break;
584 case 3:
586 reply_size = setup_ver3_dfs_referral(pathname, ppdata, &junction, self_referral);
587 break;
589 default:
591 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
592 return -1;
596 DEBUG(10,("DFS Referral pdata:\n"));
597 dump_data(10,*ppdata,reply_size);
598 return reply_size;
601 /**********************************************************************
602 The following functions are called by the NETDFS RPC pipe functions
603 **********************************************************************/
605 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
607 pstring path;
608 pstring msdfs_link;
609 connection_struct conns;
610 connection_struct *conn = &conns;
611 int i=0;
613 if(!form_path_from_junction(jn, path, sizeof(path), conn))
614 return False;
616 /* form the msdfs_link contents */
617 pstrcpy(msdfs_link, "msdfs:");
618 for(i=0; i<jn->referral_count; i++) {
619 char* refpath = jn->referral_list[i].alternate_path;
621 trim_string(refpath, "\\", "\\");
622 if(*refpath == '\0')
623 continue;
625 if(i>0)
626 pstrcat(msdfs_link, ",");
628 pstrcat(msdfs_link, refpath);
631 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
633 if(exists)
634 if(conn->vfs_ops.unlink(conn,path)!=0)
635 return False;
637 if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
638 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
639 path, msdfs_link, strerror(errno)));
640 return False;
642 return True;
645 BOOL remove_msdfs_link(struct junction_map* jn)
647 pstring path;
648 connection_struct conns;
649 connection_struct *conn = &conns;
651 if(!form_path_from_junction(jn, path, sizeof(path), conn))
652 return False;
654 if(conn->vfs_ops.unlink(conn, path)!=0)
655 return False;
657 return True;
660 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
662 int cnt = *jn_count;
663 DIR *dirp;
664 char* dname;
665 pstring connect_path;
666 char* service_name = lp_servicename(snum);
667 connection_struct conns;
668 connection_struct *conn = &conns;
670 pstrcpy(connect_path,lp_pathname(snum));
672 if(*connect_path == '\0')
673 return False;
676 * Fake up a connection struct for the VFS layer.
679 if (!create_conn_struct(conn, snum, connect_path))
680 return False;
682 /* form a junction for the msdfs root - convention */
684 pstrpcy(jn[cnt].service_name, service_name);
685 jn[cnt].volume_name[0] = '\0';
686 jn[cnt].referral_count = 1;
688 slprintf(alt_path,sizeof(alt_path)-1"\\\\%s\\%s", global_myname, service_name);
689 jn[cnt].referral_l
692 dirp = conn->vfs_ops.opendir(conn, connect_path);
693 if(!dirp)
694 return False;
696 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
697 SMB_STRUCT_STAT st;
698 pstring pathreal;
699 fstring buf;
700 int buflen = 0;
701 pstrcpy(pathreal, connect_path);
702 pstrcat(pathreal, "/");
703 pstrcat(pathreal, dname);
705 if(conn->vfs_ops.lstat(conn,pathreal,&st) != 0) {
706 DEBUG(4,("lstat error for %s: %s\n",pathreal, strerror(errno)));
707 continue;
709 if(S_ISLNK(st.st_mode)) {
710 buflen = conn->vfs_ops.readlink(conn, pathreal, buf, sizeof(fstring));
711 buf[buflen] = '\0';
712 if(parse_symlink(buf, &(jn[cnt].referral_list), &(jn[cnt].referral_count))) {
713 pstrcpy(jn[cnt].service_name, service_name);
714 pstrcpy(jn[cnt].volume_name, dname);
715 cnt++;
720 conn->vfs_ops.closedir(conn,dirp);
721 *jn_count = cnt;
722 return True;
725 int enum_msdfs_links(struct junction_map* jn)
727 int i=0;
728 int jn_count = 0;
730 if(!lp_host_msdfs())
731 return -1;
733 for(i=0;*lp_servicename(i);i++) {
734 if(lp_msdfs_root(i))
735 form_junctions(i,jn,&jn_count);
737 return jn_count;