1/*
2   Unix SMB/CIFS implementation.
3   Name mapping code
4   Copyright (C) Jeremy Allison 1998
5   Copyright (C) Andrew Tridgell 2002
6
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.
11
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.
16
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.
20*/
21
22#include "includes.h"
23
24
25/* ************************************************************************** **
26 * Used only in do_fwd_mangled_map(), below.
27 * ************************************************************************** **
28 */
29static char *map_filename( char *s,         /* This is null terminated */
30                           const char *pattern,   /* This isn't. */
31                           int len )        /* This is the length of pattern. */
32  {
33  static pstring matching_bit;  /* The bit of the string which matches */
34                                /* a * in pattern if indeed there is a * */
35  char *sp;                     /* Pointer into s. */
36  char *pp;                     /* Pointer into p. */
37  char *match_start;            /* Where the matching bit starts. */
38  pstring pat;
39
40  StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
41  pstrcpy( matching_bit, "" );  /* Match but no star gets this. */
42  pp = pat;                     /* Initialize the pointers. */
43  sp = s;
44
45  if( strequal(s, ".") || strequal(s, ".."))
46    {
47    return NULL;                /* Do not map '.' and '..' */
48    }
49
50  if( (len == 1) && (*pattern == '*') )
51    {
52    return NULL;                /* Impossible, too ambiguous for */
53    }                           /* words! */
54
55  while( (*sp)                  /* Not the end of the string. */
56      && (*pp)                  /* Not the end of the pattern. */
57      && (*sp == *pp)           /* The two match. */
58      && (*pp != '*') )         /* No wildcard. */
59    {
60    sp++;                       /* Keep looking. */
61    pp++;
62    }
63
64  if( !*sp && !*pp )            /* End of pattern. */
65    return( matching_bit );     /* Simple match.  Return empty string. */
66
67  if( *pp == '*' )
68    {
69    pp++;                       /* Always interrested in the chacter */
70                                /* after the '*' */
71    if( !*pp )                  /* It is at the end of the pattern. */
72      {
73      StrnCpy( matching_bit, s, sp-s );
74      return( matching_bit );
75      }
76    else
77      {
78      /* The next character in pattern must match a character further */
79      /* along s than sp so look for that character. */
80      match_start = sp;
81      while( (*sp)              /* Not the end of s. */
82          && (*sp != *pp) )     /* Not the same  */
83        sp++;                   /* Keep looking. */
84      if( !*sp )                /* Got to the end without a match. */
85        {
86        return( NULL );
87        }                       /* Still hope for a match. */
88      else
89        {
90        /* Now sp should point to a matching character. */
91        StrnCpy(matching_bit, match_start, sp-match_start);
92        /* Back to needing a stright match again. */
93        while( (*sp)            /* Not the end of the string. */
94            && (*pp)            /* Not the end of the pattern. */
95            && (*sp == *pp) )   /* The two match. */
96          {
97          sp++;                 /* Keep looking. */
98          pp++;
99          }
100        if( !*sp && !*pp )      /* Both at end so it matched */
101          return( matching_bit );
102        else
103          return( NULL );
104        }
105      }
106    }
107  return( NULL );               /* No match. */
108  } /* map_filename */
109
110
111/* ************************************************************************** **
112 * MangledMap is a series of name pairs in () separated by spaces.
113 * If s matches the first of the pair then the name given is the
114 * second of the pair.  A * means any number of any character and if
115 * present in the second of the pair as well as the first the
116 * matching part of the first string takes the place of the * in the
117 * second.
118 *
119 * I wanted this so that we could have RCS files which can be used
120 * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
121 * converts the UNIX RCS file subdirectory to lowercase thus
122 * preventing mangling.
123 *
124 * See 'mangled map' in smb.conf(5).
125 *
126 * ************************************************************************** **
127 */
128static void mangled_map(char *s, const char *MangledMap)
129{
130	const char *start=MangledMap;       /* Use this to search for mappings. */
131	const char *end;                    /* Used to find the end of strings. */
132	char *match_string;
133	pstring new_string;           /* Make up the result here. */
134	char *np;                     /* Points into new_string. */
135
136	DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
137	while( *start ) {
138		while( (*start) && (*start != '(') )
139			start++;
140		if( !*start )
141			continue;                 /* Always check for the end. */
142		start++;                    /* Skip the ( */
143		end = start;                /* Search for the ' ' or a ')' */
144		DEBUG( 5, ("Start of first in pair '%s'\n", start) );
145		while( (*end) && !((*end == ' ') || (*end == ')')) )
146			end++;
147		if( !*end ) {
148			start = end;
149			continue;                 /* Always check for the end. */
150		}
151		DEBUG( 5, ("End of first in pair '%s'\n", end) );
152		if( (match_string = map_filename( s, start, end-start )) ) {
153			int size_left = sizeof(new_string) - 1;
154			DEBUG( 5, ("Found a match\n") );
155			/* Found a match. */
156			start = end + 1; /* Point to start of what it is to become. */
157			DEBUG( 5, ("Start of second in pair '%s'\n", start) );
158			end = start;
159			np = new_string;
160			while( (*end && size_left > 0)    /* Not the end of string. */
161			       && (*end != ')')      /* Not the end of the pattern. */
162			       && (*end != '*') ) {   /* Not a wildcard. */
163				*np++ = *end++;
164				size_left--;
165			}
166
167			if( !*end ) {
168				start = end;
169				continue;               /* Always check for the end. */
170			}
171			if( *end == '*' ) {
172				if (size_left > 0 )
173					safe_strcpy( np, match_string, size_left );
174				np += strlen( match_string );
175				size_left -= strlen( match_string );
176				end++;                  /* Skip the '*' */
177				while ((*end && size_left >  0)   /* Not the end of string. */
178				       && (*end != ')') /* Not the end of the pattern. */
179				       && (*end != '*')) { /* Not a wildcard. */
180					*np++ = *end++;
181					size_left--;
182				}
183			}
184			if (!*end) {
185				start = end;
186				continue;               /* Always check for the end. */
187			}
188			if (size_left > 0)
189				*np++ = '\0';             /* NULL terminate it. */
190			DEBUG(5,("End of second in pair '%s'\n", end));
191			new_string[sizeof(new_string)-1] = '\0';
192			pstrcpy( s, new_string );  /* Substitute with the new name. */
193			DEBUG( 5, ("s is now '%s'\n", s) );
194		}
195		start = end;  /* Skip a bit which cannot be wanted anymore. */
196		start++;
197	}
198}
199
200/*
201  front end routine to the mangled map code
202  personally I think that the whole idea of "mangled map" is completely bogus
203*/
204void mangle_map_filename(fstring fname, int snum)
205{
206	char *map;
207
208	map = lp_mangled_map(snum);
209	if (!map || !*map) return;
210
211	mangled_map(fname, map);
212}
213