missed one on BUG 1195; make sure to set the private * to NULL
[Samba/gebeck_regimport.git] / source3 / smbd / dosmode.c
blob8353baeb21bdc4af9e2a107dd96d16013c233abe
1 /*
2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 /****************************************************************************
24 change a dos mode to a unix mode
25 base permission for files:
26 if inheriting
27 apply read/write bits from parent directory.
28 else
29 everybody gets read bit set
30 dos readonly is represented in unix by removing everyone's write bit
31 dos archive is represented in unix by the user's execute bit
32 dos system is represented in unix by the group's execute bit
33 dos hidden is represented in unix by the other's execute bit
34 if !inheriting {
35 Then apply create mask,
36 then add force bits.
38 base permission for directories:
39 dos directory is represented in unix by unix's dir bit and the exec bit
40 if !inheriting {
41 Then apply create mask,
42 then add force bits.
44 ****************************************************************************/
45 mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
47 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
48 mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
50 if ( !IS_DOS_READONLY(dosmode) )
51 result |= (S_IWUSR | S_IWGRP | S_IWOTH);
53 if (fname && lp_inherit_perms(SNUM(conn))) {
54 char *dname;
55 SMB_STRUCT_STAT sbuf;
57 dname = parent_dirname(fname);
58 DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
59 if (SMB_VFS_STAT(conn,dname,&sbuf) != 0) {
60 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
61 return(0); /* *** shouldn't happen! *** */
64 /* Save for later - but explicitly remove setuid bit for safety. */
65 dir_mode = sbuf.st_mode & ~S_ISUID;
66 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
67 /* Clear "result" */
68 result = 0;
71 if (IS_DOS_DIR(dosmode)) {
72 /* We never make directories read only for the owner as under DOS a user
73 can always create a file in a read-only directory. */
74 result |= (S_IFDIR | S_IWUSR);
76 if (dir_mode) {
77 /* Inherit mode of parent directory. */
78 result |= dir_mode;
79 } else {
80 /* Provisionally add all 'x' bits */
81 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
83 /* Apply directory mask */
84 result &= lp_dir_mask(SNUM(conn));
85 /* Add in force bits */
86 result |= lp_force_dir_mode(SNUM(conn));
88 } else {
89 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
90 result |= S_IXUSR;
92 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
93 result |= S_IXGRP;
95 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
96 result |= S_IXOTH;
98 if (dir_mode) {
99 /* Inherit 666 component of parent directory mode */
100 result |= dir_mode
101 & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
102 } else {
103 /* Apply mode mask */
104 result &= lp_create_mask(SNUM(conn));
105 /* Add in force bits */
106 result |= lp_force_create_mode(SNUM(conn));
110 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
111 return(result);
114 /****************************************************************************
115 change a unix mode to a dos mode
116 ****************************************************************************/
118 uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf)
120 int result = 0;
122 if ((sbuf->st_mode & S_IWUSR) == 0)
123 result |= aRONLY;
125 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
126 result |= aARCH;
128 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
129 result |= aSYSTEM;
131 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
132 result |= aHIDDEN;
134 if (S_ISDIR(sbuf->st_mode))
135 result = aDIR | (result & aRONLY);
137 #if defined (HAVE_STAT_ST_BLOCKS) && defined (HAVE_STAT_ST_BLKSIZE)
138 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)sbuf->st_blksize) {
139 result |= FILE_ATTRIBUTE_SPARSE;
141 #endif
143 #ifdef S_ISLNK
144 #if LINKS_READ_ONLY
145 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
146 result |= aRONLY;
147 #endif
148 #endif
150 DEBUG(8,("dos_mode_from_sbuf returning "));
152 if (result & aHIDDEN) DEBUG(8, ("h"));
153 if (result & aRONLY ) DEBUG(8, ("r"));
154 if (result & aSYSTEM) DEBUG(8, ("s"));
155 if (result & aDIR ) DEBUG(8, ("d"));
156 if (result & aARCH ) DEBUG(8, ("a"));
158 DEBUG(8,("\n"));
159 return result;
162 /****************************************************************************
163 change a unix mode to a dos mode
164 ****************************************************************************/
165 uint32 dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
167 int result = 0;
169 DEBUG(8,("dos_mode: %s\n", path));
171 result = dos_mode_from_sbuf(conn, sbuf);
173 /* Now do any modifications that depend on the path name. */
174 /* hide files with a name starting with a . */
175 if (lp_hide_dot_files(SNUM(conn))) {
176 char *p = strrchr_m(path,'/');
177 if (p)
178 p++;
179 else
180 p = path;
182 if (p[0] == '.' && p[1] != '.' && p[1] != 0)
183 result |= aHIDDEN;
186 /* Optimization : Only call is_hidden_path if it's not already
187 hidden. */
188 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
189 result |= aHIDDEN;
192 DEBUG(8,("dos_mode returning "));
194 if (result & aHIDDEN) DEBUG(8, ("h"));
195 if (result & aRONLY ) DEBUG(8, ("r"));
196 if (result & aSYSTEM) DEBUG(8, ("s"));
197 if (result & aDIR ) DEBUG(8, ("d"));
198 if (result & aARCH ) DEBUG(8, ("a"));
200 DEBUG(8,("\n"));
202 return(result);
205 /*******************************************************************
206 chmod a file - but preserve some bits
207 ********************************************************************/
209 int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_STAT *st)
211 SMB_STRUCT_STAT st1;
212 int mask=0;
213 mode_t tmp;
214 mode_t unixmode;
215 int ret = -1;
217 if (!st) {
218 st = &st1;
219 if (SMB_VFS_STAT(conn,fname,st))
220 return(-1);
223 get_acl_group_bits(conn, fname, &st->st_mode);
225 if (S_ISDIR(st->st_mode))
226 dosmode |= aDIR;
227 else
228 dosmode &= ~aDIR;
230 if (dos_mode(conn,fname,st) == dosmode)
231 return(0);
233 unixmode = unix_mode(conn,dosmode,fname);
235 /* preserve the s bits */
236 mask |= (S_ISUID | S_ISGID);
238 /* preserve the t bit */
239 #ifdef S_ISVTX
240 mask |= S_ISVTX;
241 #endif
243 /* possibly preserve the x bits */
244 if (!MAP_ARCHIVE(conn))
245 mask |= S_IXUSR;
246 if (!MAP_SYSTEM(conn))
247 mask |= S_IXGRP;
248 if (!MAP_HIDDEN(conn))
249 mask |= S_IXOTH;
251 unixmode |= (st->st_mode & mask);
253 /* if we previously had any r bits set then leave them alone */
254 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
255 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
256 unixmode |= tmp;
259 /* if we previously had any w bits set then leave them alone
260 whilst adding in the new w bits, if the new mode is not rdonly */
261 if (!IS_DOS_READONLY(dosmode)) {
262 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
265 if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0)
266 return 0;
268 if((errno != EPERM) && (errno != EACCES))
269 return -1;
271 if(!lp_dos_filemode(SNUM(conn)))
272 return -1;
274 /* We want DOS semantics, ie allow non owner with write permission to change the
275 bits on a file. Just like file_utime below.
278 /* Check if we have write access. */
279 if (CAN_WRITE(conn)) {
281 * We need to open the file with write access whilst
282 * still in our current user context. This ensures we
283 * are not violating security in doing the fchmod.
284 * This file open does *not* break any oplocks we are
285 * holding. We need to review this.... may need to
286 * break batch oplocks open by others. JRA.
288 files_struct *fsp = open_file_fchmod(conn,fname,st);
289 if (!fsp)
290 return -1;
291 become_root();
292 ret = SMB_VFS_FCHMOD(fsp, fsp->fd, unixmode);
293 unbecome_root();
294 close_file_fchmod(fsp);
297 return( ret );
301 /*******************************************************************
302 Wrapper around dos_utime that possibly allows DOS semantics rather
303 than POSIX.
304 *******************************************************************/
305 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
307 extern struct current_user current_user;
308 SMB_STRUCT_STAT sb;
309 int ret = -1;
311 errno = 0;
313 if(SMB_VFS_UTIME(conn,fname, times) == 0)
314 return 0;
316 if((errno != EPERM) && (errno != EACCES))
317 return -1;
319 if(!lp_dos_filetimes(SNUM(conn)))
320 return -1;
322 /* We have permission (given by the Samba admin) to
323 break POSIX semantics and allow a user to change
324 the time on a file they don't own but can write to
325 (as DOS does).
328 if(SMB_VFS_STAT(conn,fname,&sb) != 0)
329 return -1;
331 /* Check if we have write access. */
332 if (CAN_WRITE(conn)) {
333 if (((sb.st_mode & S_IWOTH) ||
334 conn->admin_user ||
335 ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
336 ((sb.st_mode & S_IWGRP) &&
337 in_group(sb.st_gid,current_user.gid,
338 current_user.ngroups,current_user.groups)))) {
339 /* We are allowed to become root and change the filetime. */
340 become_root();
341 ret = SMB_VFS_UTIME(conn,fname, times);
342 unbecome_root();
346 return ret;
349 /*******************************************************************
350 Change a filetime - possibly allowing DOS semantics.
351 *******************************************************************/
352 BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
354 struct utimbuf times;
356 if (null_mtime(mtime)) return(True);
358 times.modtime = times.actime = mtime;
360 if (file_utime(conn, fname, &times)) {
361 DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
362 return False;
365 return(True);