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