1 /*
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    Copyright (C) Bjoern Jacke    2006-2007
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 3 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, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "includes.h"
24 #include "system/syslog.h"
25 #include "system/capability.h"
26 #include "system/passwd.h"
27 #include "system/filesys.h"
28 #include "../lib/util/setid.h"
29 
30 #ifdef HAVE_SYS_SYSCTL_H
31 #include <sys/sysctl.h>
32 #endif
33 
34 #ifdef HAVE_SYS_PRCTL_H
35 #include <sys/prctl.h>
36 #endif
37 
38 /*
39    The idea is that this file will eventually have wrappers around all
40    important system calls in samba. The aims are:
41 
42    - to enable easier porting by putting OS dependent stuff in here
43 
44    - to allow for hooks into other "pseudo-filesystems"
45 
46    - to allow easier integration of things like the japanese extensions
47 
48    - to support the philosophy of Samba to expose the features of
49      the OS within the SMB model. In general whatever file/printer/variable
50      expansions/etc make sense to the OS should be acceptable to Samba.
51 */
52 
53 /*******************************************************************
54 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
55 ********************************************************************/
56 
sys_send(int s,const void * msg,size_t len,int flags)57 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
58 {
59 	ssize_t ret;
60 
61 	do {
62 		ret = send(s, msg, len, flags);
63 	} while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
64 
65 	return ret;
66 }
67 
68 /*******************************************************************
69 A recvfrom wrapper that will deal with EINTR.
70 NB. As used with non-blocking sockets, return on EAGAIN/EWOULDBLOCK
71 ********************************************************************/
72 
sys_recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)73 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
74 {
75 	ssize_t ret;
76 
77 	do {
78 		ret = recvfrom(s, buf, len, flags, from, fromlen);
79 	} while (ret == -1 && (errno == EINTR));
80 	return ret;
81 }
82 
83 /*******************************************************************
84 A fcntl wrapper that will deal with EINTR.
85 ********************************************************************/
86 
sys_fcntl_ptr(int fd,int cmd,void * arg)87 int sys_fcntl_ptr(int fd, int cmd, void *arg)
88 {
89 	int ret;
90 
91 	do {
92 		ret = fcntl(fd, cmd, arg);
93 	} while (ret == -1 && errno == EINTR);
94 	return ret;
95 }
96 
97 /*******************************************************************
98 A fcntl wrapper that will deal with EINTR.
99 ********************************************************************/
100 
sys_fcntl_long(int fd,int cmd,long arg)101 int sys_fcntl_long(int fd, int cmd, long arg)
102 {
103 	int ret;
104 
105 	do {
106 		ret = fcntl(fd, cmd, arg);
107 	} while (ret == -1 && errno == EINTR);
108 	return ret;
109 }
110 
111 /*******************************************************************
112 A fcntl wrapper that will deal with EINTR.
113 ********************************************************************/
114 
sys_fcntl_int(int fd,int cmd,int arg)115 int sys_fcntl_int(int fd, int cmd, int arg)
116 {
117 	int ret;
118 
119 	do {
120 		ret = fcntl(fd, cmd, arg);
121 	} while (ret == -1 && errno == EINTR);
122 	return ret;
123 }
124 
125 /****************************************************************************
126  Get/Set all the possible time fields from a stat struct as a timespec.
127 ****************************************************************************/
128 
get_atimespec(const struct stat * pst)129 static struct timespec get_atimespec(const struct stat *pst)
130 {
131 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
132 	struct timespec ret;
133 
134 	/* Old system - no ns timestamp. */
135 	ret.tv_sec = pst->st_atime;
136 	ret.tv_nsec = 0;
137 	return ret;
138 #else
139 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
140 	struct timespec ret;
141 	ret.tv_sec = pst->st_atim.tv_sec;
142 	ret.tv_nsec = pst->st_atim.tv_nsec;
143 	return ret;
144 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
145 	struct timespec ret;
146 	ret.tv_sec = pst->st_atime;
147 	ret.tv_nsec = pst->st_atimensec;
148 	return ret;
149 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
150 	struct timespec ret;
151 	ret.tv_sec = pst->st_atime;
152 	ret.tv_nsec = pst->st_atime_n;
153 	return ret;
154 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
155 	struct timespec ret;
156 	ret.tv_sec = pst->st_atime;
157 	ret.tv_nsec = pst->st_uatime * 1000;
158 	return ret;
159 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
160 	return pst->st_atimespec;
161 #else
162 #error	CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
163 #endif
164 #endif
165 }
166 
get_mtimespec(const struct stat * pst)167 static struct timespec get_mtimespec(const struct stat *pst)
168 {
169 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
170 	struct timespec ret;
171 
172 	/* Old system - no ns timestamp. */
173 	ret.tv_sec = pst->st_mtime;
174 	ret.tv_nsec = 0;
175 	return ret;
176 #else
177 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
178 	struct timespec ret;
179 	ret.tv_sec = pst->st_mtim.tv_sec;
180 	ret.tv_nsec = pst->st_mtim.tv_nsec;
181 	return ret;
182 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
183 	struct timespec ret;
184 	ret.tv_sec = pst->st_mtime;
185 	ret.tv_nsec = pst->st_mtimensec;
186 	return ret;
187 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
188 	struct timespec ret;
189 	ret.tv_sec = pst->st_mtime;
190 	ret.tv_nsec = pst->st_mtime_n;
191 	return ret;
192 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
193 	struct timespec ret;
194 	ret.tv_sec = pst->st_mtime;
195 	ret.tv_nsec = pst->st_umtime * 1000;
196 	return ret;
197 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
198 	return pst->st_mtimespec;
199 #else
200 #error	CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
201 #endif
202 #endif
203 }
204 
get_ctimespec(const struct stat * pst)205 static struct timespec get_ctimespec(const struct stat *pst)
206 {
207 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
208 	struct timespec ret;
209 
210 	/* Old system - no ns timestamp. */
211 	ret.tv_sec = pst->st_ctime;
212 	ret.tv_nsec = 0;
213 	return ret;
214 #else
215 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
216 	struct timespec ret;
217 	ret.tv_sec = pst->st_ctim.tv_sec;
218 	ret.tv_nsec = pst->st_ctim.tv_nsec;
219 	return ret;
220 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
221 	struct timespec ret;
222 	ret.tv_sec = pst->st_ctime;
223 	ret.tv_nsec = pst->st_ctimensec;
224 	return ret;
225 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
226 	struct timespec ret;
227 	ret.tv_sec = pst->st_ctime;
228 	ret.tv_nsec = pst->st_ctime_n;
229 	return ret;
230 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
231 	struct timespec ret;
232 	ret.tv_sec = pst->st_ctime;
233 	ret.tv_nsec = pst->st_uctime * 1000;
234 	return ret;
235 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
236 	return pst->st_ctimespec;
237 #else
238 #error	CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
239 #endif
240 #endif
241 }
242 
243 /****************************************************************************
244  Return the best approximation to a 'create time' under UNIX from a stat
245  structure.
246 ****************************************************************************/
247 
calc_create_time_stat(const struct stat * st)248 static struct timespec calc_create_time_stat(const struct stat *st)
249 {
250 	struct timespec ret, ret1;
251 	struct timespec c_time = get_ctimespec(st);
252 	struct timespec m_time = get_mtimespec(st);
253 	struct timespec a_time = get_atimespec(st);
254 
255 	ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
256 	ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
257 
258 	if(!null_timespec(ret1)) {
259 		return ret1;
260 	}
261 
262 	/*
263 	 * One of ctime, mtime or atime was zero (probably atime).
264 	 * Just return MIN(ctime, mtime).
265 	 */
266 	return ret;
267 }
268 
269 /****************************************************************************
270  Return the best approximation to a 'create time' under UNIX from a stat_ex
271  structure.
272 ****************************************************************************/
273 
calc_create_time_stat_ex(const struct stat_ex * st)274 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
275 {
276 	struct timespec ret, ret1;
277 	struct timespec c_time = st->st_ex_ctime;
278 	struct timespec m_time = st->st_ex_mtime;
279 	struct timespec a_time = st->st_ex_atime;
280 
281 	ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
282 	ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
283 
284 	if(!null_timespec(ret1)) {
285 		return ret1;
286 	}
287 
288 	/*
289 	 * One of ctime, mtime or atime was zero (probably atime).
290 	 * Just return MIN(ctime, mtime).
291 	 */
292 	return ret;
293 }
294 
295 /****************************************************************************
296  Return the 'create time' from a stat struct if it exists (birthtime) or else
297  use the best approximation.
298 ****************************************************************************/
299 
make_create_timespec(const struct stat * pst,struct stat_ex * dst,bool fake_dir_create_times)300 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
301 				 bool fake_dir_create_times)
302 {
303 	if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
304 		dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
305 		dst->st_ex_btime.tv_nsec = 0;
306 	}
307 
308 	dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
309 
310 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
311 	dst->st_ex_btime = pst->st_birthtimespec;
312 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
313 	dst->st_ex_btime.tv_sec = pst->st_birthtime;
314 	dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
315 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
316 	dst->st_ex_btime.tv_sec = pst->st_birthtime;
317 	dst->st_ex_btime.tv_nsec = 0;
318 #else
319 	dst->st_ex_btime = calc_create_time_stat(pst);
320 	dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
321 #endif
322 
323 	/* Deal with systems that don't initialize birthtime correctly.
324 	 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
325 	 */
326 	if (null_timespec(dst->st_ex_btime)) {
327 		dst->st_ex_btime = calc_create_time_stat(pst);
328 		dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
329 	}
330 
331 	dst->st_ex_itime = dst->st_ex_btime;
332 	dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
333 }
334 
335 /****************************************************************************
336  If we update a timestamp in a stat_ex struct we may have to recalculate
337  the birthtime. For now only implement this for write time, but we may
338  also need to do it for atime and ctime. JRA.
339 ****************************************************************************/
340 
update_stat_ex_mtime(struct stat_ex * dst,struct timespec write_ts)341 void update_stat_ex_mtime(struct stat_ex *dst,
342 				struct timespec write_ts)
343 {
344 	dst->st_ex_mtime = write_ts;
345 
346 	/* We may have to recalculate btime. */
347 	if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
348 		dst->st_ex_btime = calc_create_time_stat_ex(dst);
349 	}
350 }
351 
update_stat_ex_create_time(struct stat_ex * dst,struct timespec create_time)352 void update_stat_ex_create_time(struct stat_ex *dst,
353                                 struct timespec create_time)
354 {
355 	dst->st_ex_btime = create_time;
356 	dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
357 }
358 
update_stat_ex_itime(struct stat_ex * dst,struct timespec itime)359 void update_stat_ex_itime(struct stat_ex *dst,
360 			  struct timespec itime)
361 {
362 	dst->st_ex_itime = itime;
363 	dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME;
364 }
365 
update_stat_ex_file_id(struct stat_ex * dst,uint64_t file_id)366 void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id)
367 {
368 	dst->st_ex_file_id = file_id;
369 	dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_FILE_ID;
370 }
371 
update_stat_ex_from_saved_stat(struct stat_ex * dst,const struct stat_ex * src)372 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
373 				    const struct stat_ex *src)
374 {
375 	if (!VALID_STAT(*src)) {
376 		return;
377 	}
378 
379 	if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
380 		update_stat_ex_create_time(dst, src->st_ex_btime);
381 	}
382 
383 	if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
384 		update_stat_ex_itime(dst, src->st_ex_itime);
385 	}
386 
387 	if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
388 		update_stat_ex_file_id(dst, src->st_ex_file_id);
389 	}
390 }
391 
init_stat_ex_from_stat(struct stat_ex * dst,const struct stat * src,bool fake_dir_create_times)392 void init_stat_ex_from_stat (struct stat_ex *dst,
393 			    const struct stat *src,
394 			    bool fake_dir_create_times)
395 {
396 	dst->st_ex_dev = src->st_dev;
397 	dst->st_ex_ino = src->st_ino;
398 	dst->st_ex_mode = src->st_mode;
399 	dst->st_ex_nlink = src->st_nlink;
400 	dst->st_ex_uid = src->st_uid;
401 	dst->st_ex_gid = src->st_gid;
402 	dst->st_ex_rdev = src->st_rdev;
403 	dst->st_ex_size = src->st_size;
404 	dst->st_ex_atime = get_atimespec(src);
405 	dst->st_ex_mtime = get_mtimespec(src);
406 	dst->st_ex_ctime = get_ctimespec(src);
407 	dst->st_ex_iflags = 0;
408 	make_create_timespec(src, dst, fake_dir_create_times);
409 #ifdef HAVE_STAT_ST_BLKSIZE
410 	dst->st_ex_blksize = src->st_blksize;
411 #else
412 	dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
413 #endif
414 
415 #ifdef HAVE_STAT_ST_BLOCKS
416 	dst->st_ex_blocks = src->st_blocks;
417 #else
418 	dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
419 #endif
420 
421 #ifdef HAVE_STAT_ST_FLAGS
422 	dst->st_ex_flags = src->st_flags;
423 #else
424 	dst->st_ex_flags = 0;
425 #endif
426 	dst->st_ex_file_id = dst->st_ex_ino;
427 	dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
428 }
429 
430 /*******************************************************************
431 A stat() wrapper.
432 ********************************************************************/
433 
sys_stat(const char * fname,SMB_STRUCT_STAT * sbuf,bool fake_dir_create_times)434 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
435 	     bool fake_dir_create_times)
436 {
437 	int ret;
438 	struct stat statbuf;
439 	ret = stat(fname, &statbuf);
440 	if (ret == 0) {
441 		/* we always want directories to appear zero size */
442 		if (S_ISDIR(statbuf.st_mode)) {
443 			statbuf.st_size = 0;
444 		}
445 		init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
446 	}
447 	return ret;
448 }
449 
450 /*******************************************************************
451  An fstat() wrapper.
452 ********************************************************************/
453 
sys_fstat(int fd,SMB_STRUCT_STAT * sbuf,bool fake_dir_create_times)454 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
455 {
456 	int ret;
457 	struct stat statbuf;
458 	ret = fstat(fd, &statbuf);
459 	if (ret == 0) {
460 		/* we always want directories to appear zero size */
461 		if (S_ISDIR(statbuf.st_mode)) {
462 			statbuf.st_size = 0;
463 		}
464 		init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
465 	}
466 	return ret;
467 }
468 
469 /*******************************************************************
470  An lstat() wrapper.
471 ********************************************************************/
472 
sys_lstat(const char * fname,SMB_STRUCT_STAT * sbuf,bool fake_dir_create_times)473 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
474 	      bool fake_dir_create_times)
475 {
476 	int ret;
477 	struct stat statbuf;
478 	ret = lstat(fname, &statbuf);
479 	if (ret == 0) {
480 		/* we always want directories to appear zero size */
481 		if (S_ISDIR(statbuf.st_mode)) {
482 			statbuf.st_size = 0;
483 		}
484 		init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
485 	}
486 	return ret;
487 }
488 
489 /*******************************************************************
490  An posix_fallocate() wrapper.
491 ********************************************************************/
sys_posix_fallocate(int fd,off_t offset,off_t len)492 int sys_posix_fallocate(int fd, off_t offset, off_t len)
493 {
494 #if defined(HAVE_POSIX_FALLOCATE)
495 	return posix_fallocate(fd, offset, len);
496 #elif defined(F_RESVSP64)
497 	/* this handles XFS on IRIX */
498 	struct flock64 fl;
499 	off_t new_len = offset + len;
500 	int ret;
501 	struct stat64 sbuf;
502 
503 	/* unlikely to get a too large file on a 64bit system but ... */
504 	if (new_len < 0)
505 		return EFBIG;
506 
507 	fl.l_whence = SEEK_SET;
508 	fl.l_start = offset;
509 	fl.l_len = len;
510 
511 	ret=fcntl(fd, F_RESVSP64, &fl);
512 
513 	if (ret != 0)
514 		return errno;
515 
516 	/* Make sure the file gets enlarged after we allocated space: */
517 	fstat64(fd, &sbuf);
518 	if (new_len > sbuf.st_size)
519 		ftruncate64(fd, new_len);
520 	return 0;
521 #else
522 	return ENOSYS;
523 #endif
524 }
525 
526 /*******************************************************************
527  An fallocate() function that matches the semantics of the Linux one.
528 ********************************************************************/
529 
530 #ifdef HAVE_LINUX_FALLOC_H
531 #include <linux/falloc.h>
532 #endif
533 
sys_fallocate(int fd,uint32_t mode,off_t offset,off_t len)534 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
535 {
536 #if defined(HAVE_LINUX_FALLOCATE)
537 	int lmode = 0;
538 
539 	if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
540 		lmode |= FALLOC_FL_KEEP_SIZE;
541 		mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
542 	}
543 
544 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
545 	if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
546 		lmode |= FALLOC_FL_PUNCH_HOLE;
547 		mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
548 	}
549 #endif	/* HAVE_FALLOC_FL_PUNCH_HOLE */
550 
551 	if (mode != 0) {
552 		DEBUG(2, ("unmapped fallocate flags: %lx\n",
553 		      (unsigned long)mode));
554 		errno = EINVAL;
555 		return -1;
556 	}
557 	return fallocate(fd, lmode, offset, len);
558 #else	/* HAVE_LINUX_FALLOCATE */
559 	/* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
560 	errno = ENOSYS;
561 	return -1;
562 #endif	/* HAVE_LINUX_FALLOCATE */
563 }
564 
565 #ifdef HAVE_KERNEL_SHARE_MODES
566 #ifndef LOCK_MAND
567 #define LOCK_MAND	32	/* This is a mandatory flock */
568 #define LOCK_READ	64	/* ... Which allows concurrent read operations */
569 #define LOCK_WRITE	128	/* ... Which allows concurrent write operations */
570 #define LOCK_RW		192	/* ... Which allows concurrent read & write ops */
571 #endif
572 #endif
573 
574 /*******************************************************************
575  A flock() wrapper that will perform the kernel flock.
576 ********************************************************************/
577 
kernel_flock(int fd,uint32_t share_access,uint32_t access_mask)578 void kernel_flock(int fd, uint32_t share_access, uint32_t access_mask)
579 {
580 #ifdef HAVE_KERNEL_SHARE_MODES
581 	int kernel_mode = 0;
582 	if (share_access == FILE_SHARE_WRITE) {
583 		kernel_mode = LOCK_MAND|LOCK_WRITE;
584 	} else if (share_access == FILE_SHARE_READ) {
585 		kernel_mode = LOCK_MAND|LOCK_READ;
586 	} else if (share_access == FILE_SHARE_NONE) {
587 		kernel_mode = LOCK_MAND;
588 	}
589 	if (kernel_mode) {
590 		flock(fd, kernel_mode);
591 	}
592 #endif
593 	;
594 }
595 
596 
597 
598 /*******************************************************************
599  An fdopendir wrapper.
600 ********************************************************************/
601 
sys_fdopendir(int fd)602 DIR *sys_fdopendir(int fd)
603 {
604 #if defined(HAVE_FDOPENDIR)
605 	return fdopendir(fd);
606 #else
607 	errno = ENOSYS;
608 	return NULL;
609 #endif
610 }
611 
612 /*******************************************************************
613  An mknod() wrapper.
614 ********************************************************************/
615 
sys_mknod(const char * path,mode_t mode,SMB_DEV_T dev)616 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
617 {
618 #if defined(HAVE_MKNOD)
619 	return mknod(path, mode, dev);
620 #else
621 	/* No mknod system call. */
622 	errno = ENOSYS;
623 	return -1;
624 #endif
625 }
626 
627 /*******************************************************************
628  A mknodat() wrapper.
629 ********************************************************************/
630 
sys_mknodat(int dirfd,const char * path,mode_t mode,SMB_DEV_T dev)631 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
632 {
633 #if defined(HAVE_MKNODAT)
634 	return mknodat(dirfd, path, mode, dev);
635 #else
636 	/* No mknod system call. */
637 	errno = ENOSYS;
638 	return -1;
639 #endif
640 }
641 
642 /*******************************************************************
643  System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
644  on error (malloc fail usually).
645 ********************************************************************/
646 
sys_getwd(void)647 char *sys_getwd(void)
648 {
649 #ifdef GETCWD_TAKES_NULL
650 	return getcwd(NULL, 0);
651 #elif defined(HAVE_GETCWD)
652 	char *wd = NULL, *s = NULL;
653 	size_t allocated = PATH_MAX;
654 
655 	while (1) {
656 		s = SMB_REALLOC_ARRAY(s, char, allocated);
657 		if (s == NULL) {
658 			return NULL;
659 		}
660 		wd = getcwd(s, allocated);
661 		if (wd) {
662 			break;
663 		}
664 		if (errno != ERANGE) {
665 			int saved_errno = errno;
666 			SAFE_FREE(s);
667 			errno = saved_errno;
668 			break;
669 		}
670 		allocated *= 2;
671 		if (allocated < PATH_MAX) {
672 			SAFE_FREE(s);
673 			break;
674 		}
675 	}
676 	return wd;
677 #else
678 	char *wd = NULL;
679 	char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
680 	if (s == NULL) {
681 		return NULL;
682 	}
683 	wd = getwd(s);
684 	if (wd == NULL) {
685 		int saved_errno = errno;
686 		SAFE_FREE(s);
687 		errno = saved_errno;
688 	}
689 	return wd;
690 #endif
691 }
692 
693 #if defined(HAVE_POSIX_CAPABILITIES)
694 
695 /**************************************************************************
696  Try and abstract process capabilities (for systems that have them).
697 ****************************************************************************/
698 
699 /* Set the POSIX capabilities needed for the given purpose into the effective
700  * capability set of the current process. Make sure they are always removed
701  * from the inheritable set, because there is no circumstance in which our
702  * children should inherit our elevated privileges.
703  */
set_process_capability(enum smbd_capability capability,bool enable)704 static bool set_process_capability(enum smbd_capability capability,
705 				   bool enable)
706 {
707 	cap_value_t cap_vals[2] = {0};
708 	int num_cap_vals = 0;
709 
710 	cap_t cap;
711 
712 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
713 	/* On Linux, make sure that any capabilities we grab are sticky
714 	 * across UID changes. We expect that this would allow us to keep both
715 	 * the effective and permitted capability sets, but as of circa 2.6.16,
716 	 * only the permitted set is kept. It is a bug (which we work around)
717 	 * that the effective set is lost, but we still require the effective
718 	 * set to be kept.
719 	 */
720 	if (!prctl(PR_GET_KEEPCAPS)) {
721 		prctl(PR_SET_KEEPCAPS, 1);
722 	}
723 #endif
724 
725 	cap = cap_get_proc();
726 	if (cap == NULL) {
727 		DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
728 			strerror(errno)));
729 		return False;
730 	}
731 
732 	switch (capability) {
733 		case KERNEL_OPLOCK_CAPABILITY:
734 #ifdef CAP_NETWORK_MGT
735 			/* IRIX has CAP_NETWORK_MGT for oplocks. */
736 			cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
737 #endif
738 			break;
739 		case DMAPI_ACCESS_CAPABILITY:
740 #ifdef CAP_DEVICE_MGT
741 			/* IRIX has CAP_DEVICE_MGT for DMAPI access. */
742 			cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
743 #elif CAP_MKNOD
744 			/* Linux has CAP_MKNOD for DMAPI access. */
745 			cap_vals[num_cap_vals++] = CAP_MKNOD;
746 #endif
747 			break;
748 		case LEASE_CAPABILITY:
749 #ifdef CAP_LEASE
750 			cap_vals[num_cap_vals++] = CAP_LEASE;
751 #endif
752 			break;
753 		case DAC_OVERRIDE_CAPABILITY:
754 #ifdef CAP_DAC_OVERRIDE
755 			cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
756 #endif
757 	}
758 
759 	SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
760 
761 	if (num_cap_vals == 0) {
762 		cap_free(cap);
763 		return True;
764 	}
765 
766 	cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
767 		enable ? CAP_SET : CAP_CLEAR);
768 
769 	/* We never want to pass capabilities down to our children, so make
770 	 * sure they are not inherited.
771 	 */
772 	cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
773 
774 	if (cap_set_proc(cap) == -1) {
775 		DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
776 			strerror(errno)));
777 		cap_free(cap);
778 		return False;
779 	}
780 
781 	cap_free(cap);
782 	return True;
783 }
784 
785 #endif /* HAVE_POSIX_CAPABILITIES */
786 
787 /****************************************************************************
788  Gain the oplock capability from the kernel if possible.
789 ****************************************************************************/
790 
set_effective_capability(enum smbd_capability capability)791 void set_effective_capability(enum smbd_capability capability)
792 {
793 #if defined(HAVE_POSIX_CAPABILITIES)
794 	set_process_capability(capability, True);
795 #endif /* HAVE_POSIX_CAPABILITIES */
796 }
797 
drop_effective_capability(enum smbd_capability capability)798 void drop_effective_capability(enum smbd_capability capability)
799 {
800 #if defined(HAVE_POSIX_CAPABILITIES)
801 	set_process_capability(capability, False);
802 #endif /* HAVE_POSIX_CAPABILITIES */
803 }
804 
805 /**************************************************************************
806  Wrapper for random().
807 ****************************************************************************/
808 
sys_random(void)809 long sys_random(void)
810 {
811 #if defined(HAVE_RANDOM)
812 	return (long)random();
813 #elif defined(HAVE_RAND)
814 	return (long)rand();
815 #else
816 	DEBUG(0,("Error - no random function available !\n"));
817 	exit(1);
818 #endif
819 }
820 
821 /**************************************************************************
822  Wrapper for srandom().
823 ****************************************************************************/
824 
sys_srandom(unsigned int seed)825 void sys_srandom(unsigned int seed)
826 {
827 #if defined(HAVE_SRANDOM)
828 	srandom(seed);
829 #elif defined(HAVE_SRAND)
830 	srand(seed);
831 #else
832 	DEBUG(0,("Error - no srandom function available !\n"));
833 	exit(1);
834 #endif
835 }
836 
837 #ifndef NGROUPS_MAX
838 #define NGROUPS_MAX 32 /* Guess... */
839 #endif
840 
841 /**************************************************************************
842  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
843 ****************************************************************************/
844 
groups_max(void)845 int groups_max(void)
846 {
847 #if defined(SYSCONF_SC_NGROUPS_MAX)
848 	int ret = sysconf(_SC_NGROUPS_MAX);
849 	return (ret == -1) ? NGROUPS_MAX : ret;
850 #else
851 	return NGROUPS_MAX;
852 #endif
853 }
854 
855 /**************************************************************************
856  Wrap setgroups and getgroups for systems that declare getgroups() as
857  returning an array of gid_t, but actuall return an array of int.
858 ****************************************************************************/
859 
860 #if defined(HAVE_BROKEN_GETGROUPS)
861 
862 #ifdef HAVE_BROKEN_GETGROUPS
863 #define GID_T int
864 #else
865 #define GID_T gid_t
866 #endif
867 
sys_broken_getgroups(int setlen,gid_t * gidset)868 static int sys_broken_getgroups(int setlen, gid_t *gidset)
869 {
870 	GID_T *group_list;
871 	int i, ngroups;
872 
873 	if(setlen == 0) {
874 		return getgroups(0, NULL);
875 	}
876 
877 	/*
878 	 * Broken case. We need to allocate a
879 	 * GID_T array of size setlen.
880 	 */
881 
882 	if(setlen < 0) {
883 		errno = EINVAL;
884 		return -1;
885 	}
886 
887 	if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
888 		DEBUG(0,("sys_getgroups: Malloc fail.\n"));
889 		return -1;
890 	}
891 
892 	if((ngroups = getgroups(setlen, group_list)) < 0) {
893 		int saved_errno = errno;
894 		SAFE_FREE(group_list);
895 		errno = saved_errno;
896 		return -1;
897 	}
898 
899 	/*
900 	 * We're safe here as if ngroups > setlen then
901 	 * getgroups *must* return EINVAL.
902 	 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
903 	 */
904 
905 	for(i = 0; i < ngroups; i++)
906 		gidset[i] = (gid_t)group_list[i];
907 
908 	SAFE_FREE(group_list);
909 	return ngroups;
910 }
911 
sys_broken_setgroups(int setlen,gid_t * gidset)912 static int sys_broken_setgroups(int setlen, gid_t *gidset)
913 {
914 	GID_T *group_list;
915 	int i ;
916 
917 	if (setlen == 0)
918 		return 0 ;
919 
920 	if (setlen < 0 || setlen > groups_max()) {
921 		errno = EINVAL;
922 		return -1;
923 	}
924 
925 	/*
926 	 * Broken case. We need to allocate a
927 	 * GID_T array of size setlen.
928 	 */
929 
930 	if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
931 		DEBUG(0,("sys_setgroups: Malloc fail.\n"));
932 		return -1;
933 	}
934 
935 	for(i = 0; i < setlen; i++)
936 		group_list[i] = (GID_T) gidset[i];
937 
938 	if(samba_setgroups(setlen, group_list) != 0) {
939 		int saved_errno = errno;
940 		SAFE_FREE(group_list);
941 		errno = saved_errno;
942 		return -1;
943 	}
944 
945 	SAFE_FREE(group_list);
946 	return 0 ;
947 }
948 
949 #endif /* HAVE_BROKEN_GETGROUPS */
950 
951 /* This is a list of systems that require the first GID passed to setgroups(2)
952  * to be the effective GID. If your system is one of these, add it here.
953  */
954 #if defined (FREEBSD) || defined (DARWINOS)
955 #define USE_BSD_SETGROUPS
956 #endif
957 
958 #if defined(USE_BSD_SETGROUPS)
959 /* Depending on the particular BSD implementation, the first GID that is
960  * passed to setgroups(2) will either be ignored or will set the credential's
961  * effective GID. In either case, the right thing to do is to guarantee that
962  * gidset[0] is the effective GID.
963  */
sys_bsd_setgroups(gid_t primary_gid,int setlen,const gid_t * gidset)964 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
965 {
966 	gid_t *new_gidset = NULL;
967 	int max;
968 	int ret;
969 
970 	/* setgroups(2) will fail with EINVAL if we pass too many groups. */
971 	max = groups_max();
972 
973 	/* No group list, just make sure we are setting the efective GID. */
974 	if (setlen == 0) {
975 		return samba_setgroups(1, &primary_gid);
976 	}
977 
978 	/* If the primary gid is not the first array element, grow the array
979 	 * and insert it at the front.
980 	 */
981 	if (gidset[0] != primary_gid) {
982 	        new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
983 	        if (new_gidset == NULL) {
984 			return -1;
985 	        }
986 
987 		memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
988 		new_gidset[0] = primary_gid;
989 		setlen++;
990 	}
991 
992 	if (setlen > max) {
993 		DEBUG(3, ("forced to truncate group list from %d to %d\n",
994 			setlen, max));
995 		setlen = max;
996 	}
997 
998 #if defined(HAVE_BROKEN_GETGROUPS)
999 	ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1000 #else
1001 	ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
1002 #endif
1003 
1004 	if (new_gidset) {
1005 		int errsav = errno;
1006 		SAFE_FREE(new_gidset);
1007 		errno = errsav;
1008 	}
1009 
1010 	return ret;
1011 }
1012 
1013 #endif /* USE_BSD_SETGROUPS */
1014 
1015 /**************************************************************************
1016  Wrapper for getgroups. Deals with broken (int) case.
1017 ****************************************************************************/
1018 
sys_getgroups(int setlen,gid_t * gidset)1019 int sys_getgroups(int setlen, gid_t *gidset)
1020 {
1021 #if defined(HAVE_BROKEN_GETGROUPS)
1022 	return sys_broken_getgroups(setlen, gidset);
1023 #else
1024 	return getgroups(setlen, gidset);
1025 #endif
1026 }
1027 
1028 /**************************************************************************
1029  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1030 ****************************************************************************/
1031 
sys_setgroups(gid_t UNUSED (primary_gid),int setlen,gid_t * gidset)1032 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1033 {
1034 #if !defined(HAVE_SETGROUPS)
1035 	errno = ENOSYS;
1036 	return -1;
1037 #endif /* HAVE_SETGROUPS */
1038 
1039 #if defined(USE_BSD_SETGROUPS)
1040 	return sys_bsd_setgroups(primary_gid, setlen, gidset);
1041 #elif defined(HAVE_BROKEN_GETGROUPS)
1042 	return sys_broken_setgroups(setlen, gidset);
1043 #else
1044 	return samba_setgroups(setlen, gidset);
1045 #endif
1046 }
1047 
1048 /****************************************************************************
1049  Return the major devicenumber for UNIX extensions.
1050 ****************************************************************************/
1051 
unix_dev_major(SMB_DEV_T dev)1052 uint32_t unix_dev_major(SMB_DEV_T dev)
1053 {
1054 #if defined(HAVE_DEVICE_MAJOR_FN)
1055         return (uint32_t)major(dev);
1056 #else
1057         return (uint32_t)(dev >> 8);
1058 #endif
1059 }
1060 
1061 /****************************************************************************
1062  Return the minor devicenumber for UNIX extensions.
1063 ****************************************************************************/
1064 
unix_dev_minor(SMB_DEV_T dev)1065 uint32_t unix_dev_minor(SMB_DEV_T dev)
1066 {
1067 #if defined(HAVE_DEVICE_MINOR_FN)
1068         return (uint32_t)minor(dev);
1069 #else
1070         return (uint32_t)(dev & 0xff);
1071 #endif
1072 }
1073 
1074 /**************************************************************************
1075  Wrapper for realpath.
1076 ****************************************************************************/
1077 
sys_realpath(const char * path)1078 char *sys_realpath(const char *path)
1079 {
1080 	char *result;
1081 
1082 #ifdef REALPATH_TAKES_NULL
1083 	result = realpath(path, NULL);
1084 #else
1085 	result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
1086 	if (result) {
1087 		char *resolved_path = realpath(path, result);
1088 		if (!resolved_path) {
1089 			SAFE_FREE(result);
1090 		} else {
1091 			/* SMB_ASSERT(result == resolved_path) ? */
1092 			result = resolved_path;
1093 		}
1094 	}
1095 #endif
1096 	return result;
1097 }
1098 
1099 #if 0
1100 /*******************************************************************
1101  Return the number of CPUs.
1102 ********************************************************************/
1103 
1104 int sys_get_number_of_cores(void)
1105 {
1106 	int ret = -1;
1107 
1108 #if defined(HAVE_SYSCONF)
1109 #if defined(_SC_NPROCESSORS_ONLN)
1110 	ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1111 #endif
1112 #if defined(_SC_NPROCESSORS_CONF)
1113 	if (ret < 1) {
1114 		ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1115 	}
1116 #endif
1117 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1118 	int name[2];
1119 	unsigned int len = sizeof(ret);
1120 
1121 	name[0] = CTL_HW;
1122 #if defined(HW_AVAILCPU)
1123 	name[1] = HW_AVAILCPU;
1124 
1125 	if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1126 		ret = -1;
1127 	}
1128 #endif
1129 #if defined(HW_NCPU)
1130 	if(ret < 1) {
1131 		name[0] = CTL_HW;
1132 		name[1] = HW_NCPU;
1133 		if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1134 			ret = -1;
1135 		}
1136 	}
1137 #endif
1138 #endif
1139 	if (ret < 1) {
1140 		ret = 1;
1141 	}
1142 	return ret;
1143 }
1144 #endif
1145