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