Delete OriginalDir stuff.
[tprouty/samba.git] / source / smbd / dosmode.c
1 #define OLD_NTDOMAIN 1
2
3 /* 
4    Unix SMB/Netbios implementation.
5    Version 1.9.
6    dos mode handling functions
7    Copyright (C) Andrew Tridgell 1992-1998
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 #include "includes.h"
25
26 extern int DEBUGLEVEL;
27
28 /****************************************************************************
29   change a dos mode to a unix mode
30     base permission for files:
31          if inheriting
32            apply read/write bits from parent directory.
33          else   
34            everybody gets read bit set
35          dos readonly is represented in unix by removing everyone's write bit
36          dos archive is represented in unix by the user's execute bit
37          dos system is represented in unix by the group's execute bit
38          dos hidden is represented in unix by the other's execute bit
39          if !inheriting {
40            Then apply create mask,
41            then add force bits.
42          }
43     base permission for directories:
44          dos directory is represented in unix by unix's dir bit and the exec bit
45          if !inheriting {
46            Then apply create mask,
47            then add force bits.
48          }
49 ****************************************************************************/
50 mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
51 {
52   mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
53   mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
54
55   if ( !IS_DOS_READONLY(dosmode) )
56     result |= (S_IWUSR | S_IWGRP | S_IWOTH);
57
58   if (fname && lp_inherit_perms(SNUM(conn))) {
59     char *dname;
60     SMB_STRUCT_STAT sbuf;
61
62     dname = parent_dirname(fname);
63     DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
64     if (dos_stat(dname,&sbuf) != 0) {
65       DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
66       return(0);      /* *** shouldn't happen! *** */
67     }
68
69     /* Save for later - but explicitly remove setuid bit for safety. */
70     dir_mode = sbuf.st_mode & ~S_ISUID;
71     DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
72     /* Clear "result" */
73     result = 0;
74   } 
75
76   if (IS_DOS_DIR(dosmode)) {
77     /* We never make directories read only for the owner as under DOS a user
78        can always create a file in a read-only directory. */
79     result |= (S_IFDIR | S_IWUSR);
80
81     if (dir_mode) {
82       /* Inherit mode of parent directory. */
83       result |= dir_mode;
84     } else {
85       /* Provisionally add all 'x' bits */
86       result |= (S_IXUSR | S_IXGRP | S_IXOTH);                 
87
88       /* Apply directory mask */
89       result &= lp_dir_mask(SNUM(conn));
90       /* Add in force bits */
91       result |= lp_force_dir_mode(SNUM(conn));
92     }
93   } else { 
94     if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
95       result |= S_IXUSR;
96
97     if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
98       result |= S_IXGRP;
99  
100     if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
101       result |= S_IXOTH;  
102
103     if (dir_mode) {
104       /* Inherit 666 component of parent directory mode */
105       result |= dir_mode
106         &  (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
107     } else {
108       /* Apply mode mask */
109       result &= lp_create_mask(SNUM(conn));
110       /* Add in force bits */
111       result |= lp_force_create_mode(SNUM(conn));
112     }
113   }
114   return(result);
115 }
116
117
118 /****************************************************************************
119   change a unix mode to a dos mode
120 ****************************************************************************/
121 int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
122 {
123   int result = 0;
124
125   DEBUG(8,("dos_mode: %s\n", path));
126
127   if ((sbuf->st_mode & S_IWUSR) == 0)
128       result |= aRONLY;
129
130   if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
131     result |= aARCH;
132
133   if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
134     result |= aSYSTEM;
135
136   if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
137     result |= aHIDDEN;   
138   
139   if (S_ISDIR(sbuf->st_mode))
140     result = aDIR | (result & aRONLY);
141  
142 #ifdef S_ISLNK
143 #if LINKS_READ_ONLY
144   if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
145     result |= aRONLY;
146 #endif
147 #endif
148
149   /* hide files with a name starting with a . */
150   if (lp_hide_dot_files(SNUM(conn)))
151     {
152       char *p = strrchr(path,'/');
153       if (p)
154         p++;
155       else
156         p = path;
157       
158       if (p[0] == '.' && p[1] != '.' && p[1] != 0)
159         result |= aHIDDEN;
160     }
161
162   /* Optimization : Only call is_hidden_path if it's not already
163      hidden. */
164   if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path))
165   {
166     result |= aHIDDEN;
167   }
168
169   DEBUG(8,("dos_mode returning "));
170
171   if (result & aHIDDEN) DEBUG(8, ("h"));
172   if (result & aRONLY ) DEBUG(8, ("r"));
173   if (result & aSYSTEM) DEBUG(8, ("s"));
174   if (result & aDIR   ) DEBUG(8, ("d"));
175   if (result & aARCH  ) DEBUG(8, ("a"));
176
177   DEBUG(8,("\n"));
178
179   return(result);
180 }
181
182 /*******************************************************************
183 chmod a file - but preserve some bits
184 ********************************************************************/
185 int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st)
186 {
187   SMB_STRUCT_STAT st1;
188   int mask=0;
189   mode_t tmp;
190   mode_t unixmode;
191
192   if (!st) {
193     st = &st1;
194     if (conn->vfs_ops.stat(dos_to_unix(fname,False),st)) return(-1);
195   }
196
197   if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
198
199   if (dos_mode(conn,fname,st) == dosmode) return(0);
200
201   unixmode = unix_mode(conn,dosmode,fname);
202
203   /* preserve the s bits */
204   mask |= (S_ISUID | S_ISGID);
205
206   /* preserve the t bit */
207 #ifdef S_ISVTX
208   mask |= S_ISVTX;
209 #endif
210
211   /* possibly preserve the x bits */
212   if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR;
213   if (!MAP_SYSTEM(conn)) mask |= S_IXGRP;
214   if (!MAP_HIDDEN(conn)) mask |= S_IXOTH;
215
216   unixmode |= (st->st_mode & mask);
217
218   /* if we previously had any r bits set then leave them alone */
219   if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
220     unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
221     unixmode |= tmp;
222   }
223
224   /* if we previously had any w bits set then leave them alone 
225    whilst adding in the new w bits, if the new mode is not rdonly */
226   if (!IS_DOS_READONLY(dosmode)) {
227     unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
228   }
229
230   return(conn->vfs_ops.chmod(dos_to_unix(fname,False),unixmode));
231 }
232
233
234 /*******************************************************************
235 Wrapper around dos_utime that possibly allows DOS semantics rather
236 than POSIX.
237 *******************************************************************/
238 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
239 {
240   extern struct current_user current_user;
241   SMB_STRUCT_STAT sb;
242   int ret = -1;
243
244   errno = 0;
245
246   if(conn->vfs_ops.utime(dos_to_unix(fname, False), times) == 0)
247     return 0;
248
249   if((errno != EPERM) && (errno != EACCES))
250     return -1;
251
252   if(!lp_dos_filetimes(SNUM(conn)))
253     return -1;
254
255   /* We have permission (given by the Samba admin) to
256      break POSIX semantics and allow a user to change
257      the time on a file they don't own but can write to
258      (as DOS does).
259    */
260
261   if(conn->vfs_ops.stat(dos_to_unix(fname,False),&sb) != 0)
262     return -1;
263
264   /* Check if we have write access. */
265   if (CAN_WRITE(conn)) {
266           if (((sb.st_mode & S_IWOTH) ||
267                conn->admin_user ||
268                ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
269                ((sb.st_mode & S_IWGRP) &&
270                 in_group(sb.st_gid,current_user.gid,
271                          current_user.ngroups,current_user.groups)))) {
272                   /* We are allowed to become root and change the filetime. */
273                   become_root();
274                   ret = conn->vfs_ops.utime(dos_to_unix(fname, False), times);
275                   unbecome_root();
276           }
277   }
278
279   return ret;
280 }
281   
282 /*******************************************************************
283 Change a filetime - possibly allowing DOS semantics.
284 *******************************************************************/
285 BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
286 {
287   struct utimbuf times;
288
289   if (null_mtime(mtime)) return(True);
290
291   times.modtime = times.actime = mtime;
292
293   if (file_utime(conn, fname, &times)) {
294     DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
295     return False;
296   }
297   
298   return(True);
299
300
301 #undef OLD_NTDOMAIN