1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.c, but not used in libdbus
3 *
4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
5 * Copyright (C) 2003 CodeFactory AB
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #include <config.h>
26 #include "dbus-sysdeps.h"
27 #include "dbus-sysdeps-unix.h"
28 #include "dbus-internals.h"
29 #include "dbus-pipe.h"
30 #include "dbus-protocol.h"
31 #include "dbus-string.h"
32 #define DBUS_USERDB_INCLUDES_PRIVATE 1
33 #include "dbus-userdb.h"
34 #include "dbus-test.h"
35
36 #include <sys/types.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #ifdef HAVE_SYS_RESOURCE_H
46 #include <sys/resource.h>
47 #endif
48 #include <grp.h>
49 #include <sys/socket.h>
50 #include <dirent.h>
51 #include <sys/un.h>
52 #include <syslog.h>
53
54 #ifdef HAVE_SYS_SYSLIMITS_H
55 #include <sys/syslimits.h>
56 #endif
57
58 #ifndef O_BINARY
59 #define O_BINARY 0
60 #endif
61
62 /**
63 * @addtogroup DBusInternalsUtils
64 * @{
65 */
66
67
68 /**
69 * Does the chdir, fork, setsid, etc. to become a daemon process.
70 *
71 * @param pidfile #NULL, or pidfile to create
72 * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none
73 * @param error return location for errors
74 * @param keep_umask #TRUE to keep the original umask
75 * @returns #FALSE on failure
76 */
77 dbus_bool_t
_dbus_become_daemon(const DBusString * pidfile,DBusPipe * print_pid_pipe,DBusError * error,dbus_bool_t keep_umask)78 _dbus_become_daemon (const DBusString *pidfile,
79 DBusPipe *print_pid_pipe,
80 DBusError *error,
81 dbus_bool_t keep_umask)
82 {
83 const char *s;
84 pid_t child_pid;
85 int dev_null_fd;
86
87 _dbus_verbose ("Becoming a daemon...\n");
88
89 _dbus_verbose ("chdir to /\n");
90 if (chdir ("/") < 0)
91 {
92 dbus_set_error (error, DBUS_ERROR_FAILED,
93 "Could not chdir() to root directory");
94 return FALSE;
95 }
96
97 _dbus_verbose ("forking...\n");
98 switch ((child_pid = fork ()))
99 {
100 case -1:
101 _dbus_verbose ("fork failed\n");
102 dbus_set_error (error, _dbus_error_from_errno (errno),
103 "Failed to fork daemon: %s", _dbus_strerror (errno));
104 return FALSE;
105 break;
106
107 case 0:
108 _dbus_verbose ("in child, closing std file descriptors\n");
109
110 /* silently ignore failures here, if someone
111 * doesn't have /dev/null we may as well try
112 * to continue anyhow
113 */
114
115 dev_null_fd = open ("/dev/null", O_RDWR);
116 if (dev_null_fd >= 0)
117 {
118 dup2 (dev_null_fd, 0);
119 dup2 (dev_null_fd, 1);
120
121 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
122 if (s == NULL || *s == '\0')
123 dup2 (dev_null_fd, 2);
124 else
125 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
126 }
127
128 if (!keep_umask)
129 {
130 /* Get a predictable umask */
131 _dbus_verbose ("setting umask\n");
132 umask (022);
133 }
134
135 _dbus_verbose ("calling setsid()\n");
136 if (setsid () == -1)
137 _dbus_assert_not_reached ("setsid() failed");
138
139 break;
140
141 default:
142 if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
143 child_pid, error))
144 {
145 _dbus_verbose ("pid file or pipe write failed: %s\n",
146 error->message);
147 kill (child_pid, SIGTERM);
148 return FALSE;
149 }
150
151 _dbus_verbose ("parent exiting\n");
152 _exit (0);
153 break;
154 }
155
156 return TRUE;
157 }
158
159
160 /**
161 * Creates a file containing the process ID.
162 *
163 * @param filename the filename to write to
164 * @param pid our process ID
165 * @param error return location for errors
166 * @returns #FALSE on failure
167 */
168 static dbus_bool_t
_dbus_write_pid_file(const DBusString * filename,unsigned long pid,DBusError * error)169 _dbus_write_pid_file (const DBusString *filename,
170 unsigned long pid,
171 DBusError *error)
172 {
173 const char *cfilename;
174 int fd;
175 FILE *f;
176
177 cfilename = _dbus_string_get_const_data (filename);
178
179 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
180
181 if (fd < 0)
182 {
183 dbus_set_error (error, _dbus_error_from_errno (errno),
184 "Failed to open \"%s\": %s", cfilename,
185 _dbus_strerror (errno));
186 return FALSE;
187 }
188
189 if ((f = fdopen (fd, "w")) == NULL)
190 {
191 dbus_set_error (error, _dbus_error_from_errno (errno),
192 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
193 _dbus_close (fd, NULL);
194 return FALSE;
195 }
196
197 if (fprintf (f, "%lu\n", pid) < 0)
198 {
199 dbus_set_error (error, _dbus_error_from_errno (errno),
200 "Failed to write to \"%s\": %s", cfilename,
201 _dbus_strerror (errno));
202
203 fclose (f);
204 return FALSE;
205 }
206
207 if (fclose (f) == EOF)
208 {
209 dbus_set_error (error, _dbus_error_from_errno (errno),
210 "Failed to close \"%s\": %s", cfilename,
211 _dbus_strerror (errno));
212 return FALSE;
213 }
214
215 return TRUE;
216 }
217
218 /**
219 * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a
220 * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both
221 * NULL.
222 *
223 * @param pidfile the file to write to or #NULL
224 * @param print_pid_pipe the pipe to write to or #NULL
225 * @param pid_to_write the pid to write out
226 * @param error error on failure
227 * @returns FALSE if error is set
228 */
229 dbus_bool_t
_dbus_write_pid_to_file_and_pipe(const DBusString * pidfile,DBusPipe * print_pid_pipe,dbus_pid_t pid_to_write,DBusError * error)230 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
231 DBusPipe *print_pid_pipe,
232 dbus_pid_t pid_to_write,
233 DBusError *error)
234 {
235 if (pidfile)
236 {
237 _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
238 if (!_dbus_write_pid_file (pidfile,
239 pid_to_write,
240 error))
241 {
242 _dbus_verbose ("pid file write failed\n");
243 _DBUS_ASSERT_ERROR_IS_SET(error);
244 return FALSE;
245 }
246 }
247 else
248 {
249 _dbus_verbose ("No pid file requested\n");
250 }
251
252 if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
253 {
254 DBusString pid;
255 int bytes;
256
257 _dbus_verbose ("writing our pid to pipe %d\n",
258 print_pid_pipe->fd);
259
260 if (!_dbus_string_init (&pid))
261 {
262 _DBUS_SET_OOM (error);
263 return FALSE;
264 }
265
266 if (!_dbus_string_append_int (&pid, pid_to_write) ||
267 !_dbus_string_append (&pid, "\n"))
268 {
269 _dbus_string_free (&pid);
270 _DBUS_SET_OOM (error);
271 return FALSE;
272 }
273
274 bytes = _dbus_string_get_length (&pid);
275 if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
276 {
277 /* _dbus_pipe_write sets error only on failure, not short write */
278 if (error != NULL && !dbus_error_is_set(error))
279 {
280 dbus_set_error (error, DBUS_ERROR_FAILED,
281 "Printing message bus PID: did not write enough bytes\n");
282 }
283 _dbus_string_free (&pid);
284 return FALSE;
285 }
286
287 _dbus_string_free (&pid);
288 }
289 else
290 {
291 _dbus_verbose ("No pid pipe to write to\n");
292 }
293
294 return TRUE;
295 }
296
297 /**
298 * Verify that after the fork we can successfully change to this user.
299 *
300 * @param user the username given in the daemon configuration
301 * @returns #TRUE if username is valid
302 */
303 dbus_bool_t
_dbus_verify_daemon_user(const char * user)304 _dbus_verify_daemon_user (const char *user)
305 {
306 DBusString u;
307
308 _dbus_string_init_const (&u, user);
309
310 return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
311 }
312
313
314 /* The HAVE_LIBAUDIT case lives in selinux.c */
315 #ifndef HAVE_LIBAUDIT
316 /**
317 * Changes the user and group the bus is running as.
318 *
319 * @param user the user to become
320 * @param error return location for errors
321 * @returns #FALSE on failure
322 */
323 dbus_bool_t
_dbus_change_to_daemon_user(const char * user,DBusError * error)324 _dbus_change_to_daemon_user (const char *user,
325 DBusError *error)
326 {
327 dbus_uid_t uid;
328 dbus_gid_t gid;
329 DBusString u;
330
331 _dbus_string_init_const (&u, user);
332
333 if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
334 {
335 dbus_set_error (error, DBUS_ERROR_FAILED,
336 "User '%s' does not appear to exist?",
337 user);
338 return FALSE;
339 }
340
341 /* setgroups() only works if we are a privileged process,
342 * so we don't return error on failure; the only possible
343 * failure is that we don't have perms to do it.
344 *
345 * not sure this is right, maybe if setuid()
346 * is going to work then setgroups() should also work.
347 */
348 if (setgroups (0, NULL) < 0)
349 _dbus_warn ("Failed to drop supplementary groups: %s\n",
350 _dbus_strerror (errno));
351
352 /* Set GID first, or the setuid may remove our permission
353 * to change the GID
354 */
355 if (setgid (gid) < 0)
356 {
357 dbus_set_error (error, _dbus_error_from_errno (errno),
358 "Failed to set GID to %lu: %s", gid,
359 _dbus_strerror (errno));
360 return FALSE;
361 }
362
363 if (setuid (uid) < 0)
364 {
365 dbus_set_error (error, _dbus_error_from_errno (errno),
366 "Failed to set UID to %lu: %s", uid,
367 _dbus_strerror (errno));
368 return FALSE;
369 }
370
371 return TRUE;
372 }
373 #endif /* !HAVE_LIBAUDIT */
374
375
376 /**
377 * Attempt to ensure that the current process can open
378 * at least @limit file descriptors.
379 *
380 * If @limit is lower than the current, it will not be
381 * lowered. No error is returned if the request can
382 * not be satisfied.
383 *
384 * @limit Number of file descriptors
385 */
386 void
_dbus_request_file_descriptor_limit(unsigned int limit)387 _dbus_request_file_descriptor_limit (unsigned int limit)
388 {
389 #ifdef HAVE_SETRLIMIT
390 struct rlimit lim;
391 struct rlimit target_lim;
392
393 /* No point to doing this practically speaking
394 * if we're not uid 0. We expect the system
395 * bus to use this before we change UID, and
396 * the session bus takes the Linux default
397 * of 1024 for both cur and max.
398 */
399 if (getuid () != 0)
400 return;
401
402 if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
403 return;
404
405 if (lim.rlim_cur >= limit)
406 return;
407
408 /* Ignore "maximum limit", assume we have the "superuser"
409 * privileges. On Linux this is CAP_SYS_RESOURCE.
410 */
411 target_lim.rlim_cur = target_lim.rlim_max = limit;
412 /* Also ignore errors; if we fail, we will at least work
413 * up to whatever limit we had, which seems better than
414 * just outright aborting.
415 *
416 * However, in the future we should probably log this so OS builders
417 * have a chance to notice any misconfiguration like dbus-daemon
418 * being started without CAP_SYS_RESOURCE.
419 */
420 setrlimit (RLIMIT_NOFILE, &target_lim);
421 #endif
422 }
423
424 void
_dbus_init_system_log(void)425 _dbus_init_system_log (void)
426 {
427 #if HAVE_DECL_LOG_PERROR
428 openlog ("dbus", LOG_PID | LOG_PERROR, LOG_DAEMON);
429 #else
430 openlog ("dbus", LOG_PID, LOG_DAEMON);
431 #endif
432 }
433
434 /**
435 * Log a message to the system log file (e.g. syslog on Unix).
436 *
437 * @param severity a severity value
438 * @param msg a printf-style format string
439 * @param args arguments for the format string
440 *
441 */
442 void
_dbus_system_log(DBusSystemLogSeverity severity,const char * msg,...)443 _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...)
444 {
445 va_list args;
446
447 va_start (args, msg);
448
449 _dbus_system_logv (severity, msg, args);
450
451 va_end (args);
452 }
453
454 /**
455 * Log a message to the system log file (e.g. syslog on Unix).
456 *
457 * @param severity a severity value
458 * @param msg a printf-style format string
459 * @param args arguments for the format string
460 *
461 * If the FATAL severity is given, this function will terminate the program
462 * with an error code.
463 */
464 void
_dbus_system_logv(DBusSystemLogSeverity severity,const char * msg,va_list args)465 _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args)
466 {
467 int flags;
468 switch (severity)
469 {
470 case DBUS_SYSTEM_LOG_INFO:
471 flags = LOG_DAEMON | LOG_NOTICE;
472 break;
473 case DBUS_SYSTEM_LOG_SECURITY:
474 flags = LOG_AUTH | LOG_NOTICE;
475 break;
476 case DBUS_SYSTEM_LOG_FATAL:
477 flags = LOG_DAEMON|LOG_CRIT;
478 break;
479 default:
480 return;
481 }
482
483 #ifndef HAVE_DECL_LOG_PERROR
484 {
485 /* vsyslog() won't write to stderr, so we'd better do it */
486 va_list tmp;
487
488 DBUS_VA_COPY (tmp, args);
489 fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ());
490 vfprintf (stderr, msg, tmp);
491 fputc ('\n', stderr);
492 va_end (tmp);
493 }
494 #endif
495
496 vsyslog (flags, msg, args);
497
498 if (severity == DBUS_SYSTEM_LOG_FATAL)
499 exit (1);
500 }
501
502 /** Installs a UNIX signal handler
503 *
504 * @param sig the signal to handle
505 * @param handler the handler
506 */
507 void
_dbus_set_signal_handler(int sig,DBusSignalHandler handler)508 _dbus_set_signal_handler (int sig,
509 DBusSignalHandler handler)
510 {
511 struct sigaction act;
512 sigset_t empty_mask;
513
514 sigemptyset (&empty_mask);
515 act.sa_handler = handler;
516 act.sa_mask = empty_mask;
517 act.sa_flags = 0;
518 sigaction (sig, &act, NULL);
519 }
520
521 /** Checks if a file exists
522 *
523 * @param file full path to the file
524 * @returns #TRUE if file exists
525 */
526 dbus_bool_t
_dbus_file_exists(const char * file)527 _dbus_file_exists (const char *file)
528 {
529 return (access (file, F_OK) == 0);
530 }
531
532 /** Checks if user is at the console
533 *
534 * @param username user to check
535 * @param error return location for errors
536 * @returns #TRUE is the user is at the consolei and there are no errors
537 */
538 dbus_bool_t
_dbus_user_at_console(const char * username,DBusError * error)539 _dbus_user_at_console (const char *username,
540 DBusError *error)
541 {
542
543 DBusString u, f;
544 dbus_bool_t result;
545
546 result = FALSE;
547 if (!_dbus_string_init (&f))
548 {
549 _DBUS_SET_OOM (error);
550 return FALSE;
551 }
552
553 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
554 {
555 _DBUS_SET_OOM (error);
556 goto out;
557 }
558
559 _dbus_string_init_const (&u, username);
560
561 if (!_dbus_concat_dir_and_file (&f, &u))
562 {
563 _DBUS_SET_OOM (error);
564 goto out;
565 }
566
567 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
568
569 out:
570 _dbus_string_free (&f);
571
572 return result;
573 }
574
575
576 /**
577 * Checks whether the filename is an absolute path
578 *
579 * @param filename the filename
580 * @returns #TRUE if an absolute path
581 */
582 dbus_bool_t
_dbus_path_is_absolute(const DBusString * filename)583 _dbus_path_is_absolute (const DBusString *filename)
584 {
585 if (_dbus_string_get_length (filename) > 0)
586 return _dbus_string_get_byte (filename, 0) == '/';
587 else
588 return FALSE;
589 }
590
591 /**
592 * stat() wrapper.
593 *
594 * @param filename the filename to stat
595 * @param statbuf the stat info to fill in
596 * @param error return location for error
597 * @returns #FALSE if error was set
598 */
599 dbus_bool_t
_dbus_stat(const DBusString * filename,DBusStat * statbuf,DBusError * error)600 _dbus_stat (const DBusString *filename,
601 DBusStat *statbuf,
602 DBusError *error)
603 {
604 const char *filename_c;
605 struct stat sb;
606
607 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
608
609 filename_c = _dbus_string_get_const_data (filename);
610
611 if (stat (filename_c, &sb) < 0)
612 {
613 dbus_set_error (error, _dbus_error_from_errno (errno),
614 "%s", _dbus_strerror (errno));
615 return FALSE;
616 }
617
618 statbuf->mode = sb.st_mode;
619 statbuf->nlink = sb.st_nlink;
620 statbuf->uid = sb.st_uid;
621 statbuf->gid = sb.st_gid;
622 statbuf->size = sb.st_size;
623 statbuf->atime = sb.st_atime;
624 statbuf->mtime = sb.st_mtime;
625 statbuf->ctime = sb.st_ctime;
626
627 return TRUE;
628 }
629
630
631 /**
632 * Internals of directory iterator
633 */
634 struct DBusDirIter
635 {
636 DIR *d; /**< The DIR* from opendir() */
637
638 };
639
640 /**
641 * Open a directory to iterate over.
642 *
643 * @param filename the directory name
644 * @param error exception return object or #NULL
645 * @returns new iterator, or #NULL on error
646 */
647 DBusDirIter*
_dbus_directory_open(const DBusString * filename,DBusError * error)648 _dbus_directory_open (const DBusString *filename,
649 DBusError *error)
650 {
651 DIR *d;
652 DBusDirIter *iter;
653 const char *filename_c;
654
655 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
656
657 filename_c = _dbus_string_get_const_data (filename);
658
659 d = opendir (filename_c);
660 if (d == NULL)
661 {
662 dbus_set_error (error, _dbus_error_from_errno (errno),
663 "Failed to read directory \"%s\": %s",
664 filename_c,
665 _dbus_strerror (errno));
666 return NULL;
667 }
668 iter = dbus_new0 (DBusDirIter, 1);
669 if (iter == NULL)
670 {
671 closedir (d);
672 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
673 "Could not allocate memory for directory iterator");
674 return NULL;
675 }
676
677 iter->d = d;
678
679 return iter;
680 }
681
682 /**
683 * Get next file in the directory. Will not return "." or ".." on
684 * UNIX. If an error occurs, the contents of "filename" are
685 * undefined. The error is never set if the function succeeds.
686 *
687 * This function is not re-entrant, and not necessarily thread-safe.
688 * Only use it for test code or single-threaded utilities.
689 *
690 * @param iter the iterator
691 * @param filename string to be set to the next file in the dir
692 * @param error return location for error
693 * @returns #TRUE if filename was filled in with a new filename
694 */
695 dbus_bool_t
_dbus_directory_get_next_file(DBusDirIter * iter,DBusString * filename,DBusError * error)696 _dbus_directory_get_next_file (DBusDirIter *iter,
697 DBusString *filename,
698 DBusError *error)
699 {
700 struct dirent *ent;
701 int err;
702
703 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
704
705 again:
706 errno = 0;
707 ent = readdir (iter->d);
708
709 if (!ent)
710 {
711 err = errno;
712
713 if (err != 0)
714 dbus_set_error (error,
715 _dbus_error_from_errno (err),
716 "%s", _dbus_strerror (err));
717
718 return FALSE;
719 }
720 else if (ent->d_name[0] == '.' &&
721 (ent->d_name[1] == '\0' ||
722 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
723 goto again;
724 else
725 {
726 _dbus_string_set_length (filename, 0);
727 if (!_dbus_string_append (filename, ent->d_name))
728 {
729 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
730 "No memory to read directory entry");
731 return FALSE;
732 }
733 else
734 {
735 return TRUE;
736 }
737 }
738 }
739
740 /**
741 * Closes a directory iteration.
742 */
743 void
_dbus_directory_close(DBusDirIter * iter)744 _dbus_directory_close (DBusDirIter *iter)
745 {
746 closedir (iter->d);
747 dbus_free (iter);
748 }
749
750 static dbus_bool_t
fill_user_info_from_group(struct group * g,DBusGroupInfo * info,DBusError * error)751 fill_user_info_from_group (struct group *g,
752 DBusGroupInfo *info,
753 DBusError *error)
754 {
755 _dbus_assert (g->gr_name != NULL);
756
757 info->gid = g->gr_gid;
758 info->groupname = _dbus_strdup (g->gr_name);
759
760 /* info->members = dbus_strdupv (g->gr_mem) */
761
762 if (info->groupname == NULL)
763 {
764 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
765 return FALSE;
766 }
767
768 return TRUE;
769 }
770
771 static dbus_bool_t
fill_group_info(DBusGroupInfo * info,dbus_gid_t gid,const DBusString * groupname,DBusError * error)772 fill_group_info (DBusGroupInfo *info,
773 dbus_gid_t gid,
774 const DBusString *groupname,
775 DBusError *error)
776 {
777 const char *group_c_str;
778
779 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
780 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
781
782 if (groupname)
783 group_c_str = _dbus_string_get_const_data (groupname);
784 else
785 group_c_str = NULL;
786
787 /* For now assuming that the getgrnam() and getgrgid() flavors
788 * always correspond to the pwnam flavors, if not we have
789 * to add more configure checks.
790 */
791
792 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
793 {
794 struct group *g;
795 int result;
796 size_t buflen;
797 char *buf;
798 struct group g_str;
799 dbus_bool_t b;
800
801 /* retrieve maximum needed size for buf */
802 buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
803
804 /* sysconf actually returns a long, but everything else expects size_t,
805 * so just recast here.
806 * https://bugs.freedesktop.org/show_bug.cgi?id=17061
807 */
808 if ((long) buflen <= 0)
809 buflen = 1024;
810
811 result = -1;
812 while (1)
813 {
814 buf = dbus_malloc (buflen);
815 if (buf == NULL)
816 {
817 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
818 return FALSE;
819 }
820
821 g = NULL;
822 #ifdef HAVE_POSIX_GETPWNAM_R
823 if (group_c_str)
824 result = getgrnam_r (group_c_str, &g_str, buf, buflen,
825 &g);
826 else
827 result = getgrgid_r (gid, &g_str, buf, buflen,
828 &g);
829 #else
830 g = getgrnam_r (group_c_str, &g_str, buf, buflen);
831 result = 0;
832 #endif /* !HAVE_POSIX_GETPWNAM_R */
833 /* Try a bigger buffer if ERANGE was returned:
834 https://bugs.freedesktop.org/show_bug.cgi?id=16727
835 */
836 if (result == ERANGE && buflen < 512 * 1024)
837 {
838 dbus_free (buf);
839 buflen *= 2;
840 }
841 else
842 {
843 break;
844 }
845 }
846
847 if (result == 0 && g == &g_str)
848 {
849 b = fill_user_info_from_group (g, info, error);
850 dbus_free (buf);
851 return b;
852 }
853 else
854 {
855 dbus_set_error (error, _dbus_error_from_errno (errno),
856 "Group %s unknown or failed to look it up\n",
857 group_c_str ? group_c_str : "???");
858 dbus_free (buf);
859 return FALSE;
860 }
861 }
862 #else /* ! HAVE_GETPWNAM_R */
863 {
864 /* I guess we're screwed on thread safety here */
865 struct group *g;
866
867 g = getgrnam (group_c_str);
868
869 if (g != NULL)
870 {
871 return fill_user_info_from_group (g, info, error);
872 }
873 else
874 {
875 dbus_set_error (error, _dbus_error_from_errno (errno),
876 "Group %s unknown or failed to look it up\n",
877 group_c_str ? group_c_str : "???");
878 return FALSE;
879 }
880 }
881 #endif /* ! HAVE_GETPWNAM_R */
882 }
883
884 /**
885 * Initializes the given DBusGroupInfo struct
886 * with information about the given group name.
887 *
888 * @param info the group info struct
889 * @param groupname name of group
890 * @param error the error return
891 * @returns #FALSE if error is set
892 */
893 dbus_bool_t
_dbus_group_info_fill(DBusGroupInfo * info,const DBusString * groupname,DBusError * error)894 _dbus_group_info_fill (DBusGroupInfo *info,
895 const DBusString *groupname,
896 DBusError *error)
897 {
898 return fill_group_info (info, DBUS_GID_UNSET,
899 groupname, error);
900
901 }
902
903 /**
904 * Initializes the given DBusGroupInfo struct
905 * with information about the given group ID.
906 *
907 * @param info the group info struct
908 * @param gid group ID
909 * @param error the error return
910 * @returns #FALSE if error is set
911 */
912 dbus_bool_t
_dbus_group_info_fill_gid(DBusGroupInfo * info,dbus_gid_t gid,DBusError * error)913 _dbus_group_info_fill_gid (DBusGroupInfo *info,
914 dbus_gid_t gid,
915 DBusError *error)
916 {
917 return fill_group_info (info, gid, NULL, error);
918 }
919
920 /**
921 * Parse a UNIX user from the bus config file. On Windows, this should
922 * simply always fail (just return #FALSE).
923 *
924 * @param username the username text
925 * @param uid_p place to return the uid
926 * @returns #TRUE on success
927 */
928 dbus_bool_t
_dbus_parse_unix_user_from_config(const DBusString * username,dbus_uid_t * uid_p)929 _dbus_parse_unix_user_from_config (const DBusString *username,
930 dbus_uid_t *uid_p)
931 {
932 return _dbus_get_user_id (username, uid_p);
933
934 }
935
936 /**
937 * Parse a UNIX group from the bus config file. On Windows, this should
938 * simply always fail (just return #FALSE).
939 *
940 * @param groupname the groupname text
941 * @param gid_p place to return the gid
942 * @returns #TRUE on success
943 */
944 dbus_bool_t
_dbus_parse_unix_group_from_config(const DBusString * groupname,dbus_gid_t * gid_p)945 _dbus_parse_unix_group_from_config (const DBusString *groupname,
946 dbus_gid_t *gid_p)
947 {
948 return _dbus_get_group_id (groupname, gid_p);
949 }
950
951 /**
952 * Gets all groups corresponding to the given UNIX user ID. On UNIX,
953 * just calls _dbus_groups_from_uid(). On Windows, should always
954 * fail since we don't know any UNIX groups.
955 *
956 * @param uid the UID
957 * @param group_ids return location for array of group IDs
958 * @param n_group_ids return location for length of returned array
959 * @returns #TRUE if the UID existed and we got some credentials
960 */
961 dbus_bool_t
_dbus_unix_groups_from_uid(dbus_uid_t uid,dbus_gid_t ** group_ids,int * n_group_ids)962 _dbus_unix_groups_from_uid (dbus_uid_t uid,
963 dbus_gid_t **group_ids,
964 int *n_group_ids)
965 {
966 return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
967 }
968
969 /**
970 * Checks to see if the UNIX user ID is at the console.
971 * Should always fail on Windows (set the error to
972 * #DBUS_ERROR_NOT_SUPPORTED).
973 *
974 * @param uid UID of person to check
975 * @param error return location for errors
976 * @returns #TRUE if the UID is the same as the console user and there are no errors
977 */
978 dbus_bool_t
_dbus_unix_user_is_at_console(dbus_uid_t uid,DBusError * error)979 _dbus_unix_user_is_at_console (dbus_uid_t uid,
980 DBusError *error)
981 {
982 return _dbus_is_console_user (uid, error);
983
984 }
985
986 /**
987 * Checks to see if the UNIX user ID matches the UID of
988 * the process. Should always return #FALSE on Windows.
989 *
990 * @param uid the UNIX user ID
991 * @returns #TRUE if this uid owns the process.
992 */
993 dbus_bool_t
_dbus_unix_user_is_process_owner(dbus_uid_t uid)994 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
995 {
996 return uid == _dbus_geteuid ();
997 }
998
999 /**
1000 * Checks to see if the Windows user SID matches the owner of
1001 * the process. Should always return #FALSE on UNIX.
1002 *
1003 * @param windows_sid the Windows user SID
1004 * @returns #TRUE if this user owns the process.
1005 */
1006 dbus_bool_t
_dbus_windows_user_is_process_owner(const char * windows_sid)1007 _dbus_windows_user_is_process_owner (const char *windows_sid)
1008 {
1009 return FALSE;
1010 }
1011
1012 /** @} */ /* End of DBusInternalsUtils functions */
1013
1014 /**
1015 * @addtogroup DBusString
1016 *
1017 * @{
1018 */
1019 /**
1020 * Get the directory name from a complete filename
1021 * @param filename the filename
1022 * @param dirname string to append directory name to
1023 * @returns #FALSE if no memory
1024 */
1025 dbus_bool_t
_dbus_string_get_dirname(const DBusString * filename,DBusString * dirname)1026 _dbus_string_get_dirname (const DBusString *filename,
1027 DBusString *dirname)
1028 {
1029 int sep;
1030
1031 _dbus_assert (filename != dirname);
1032 _dbus_assert (filename != NULL);
1033 _dbus_assert (dirname != NULL);
1034
1035 /* Ignore any separators on the end */
1036 sep = _dbus_string_get_length (filename);
1037 if (sep == 0)
1038 return _dbus_string_append (dirname, "."); /* empty string passed in */
1039
1040 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
1041 --sep;
1042
1043 _dbus_assert (sep >= 0);
1044
1045 if (sep == 0)
1046 return _dbus_string_append (dirname, "/");
1047
1048 /* Now find the previous separator */
1049 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
1050 if (sep < 0)
1051 return _dbus_string_append (dirname, ".");
1052
1053 /* skip multiple separators */
1054 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
1055 --sep;
1056
1057 _dbus_assert (sep >= 0);
1058
1059 if (sep == 0 &&
1060 _dbus_string_get_byte (filename, 0) == '/')
1061 return _dbus_string_append (dirname, "/");
1062 else
1063 return _dbus_string_copy_len (filename, 0, sep - 0,
1064 dirname, _dbus_string_get_length (dirname));
1065 }
1066 /** @} */ /* DBusString stuff */
1067
1068 static void
string_squash_nonprintable(DBusString * str)1069 string_squash_nonprintable (DBusString *str)
1070 {
1071 unsigned char *buf;
1072 int i, len;
1073
1074 buf = _dbus_string_get_data (str);
1075 len = _dbus_string_get_length (str);
1076
1077 for (i = 0; i < len; i++)
1078 {
1079 unsigned char c = (unsigned char) buf[i];
1080 if (c == '\0')
1081 buf[i] = ' ';
1082 else if (c < 0x20 || c > 127)
1083 buf[i] = '?';
1084 }
1085 }
1086
1087 /**
1088 * Get a printable string describing the command used to execute
1089 * the process with pid. This string should only be used for
1090 * informative purposes such as logging; it may not be trusted.
1091 *
1092 * The command is guaranteed to be printable ASCII and no longer
1093 * than max_len.
1094 *
1095 * @param pid Process id
1096 * @param str Append command to this string
1097 * @param max_len Maximum length of returned command
1098 * @param error return location for errors
1099 * @returns #FALSE on error
1100 */
1101 dbus_bool_t
_dbus_command_for_pid(unsigned long pid,DBusString * str,int max_len,DBusError * error)1102 _dbus_command_for_pid (unsigned long pid,
1103 DBusString *str,
1104 int max_len,
1105 DBusError *error)
1106 {
1107 /* This is all Linux-specific for now */
1108 DBusString path;
1109 DBusString cmdline;
1110 int fd;
1111
1112 if (!_dbus_string_init (&path))
1113 {
1114 _DBUS_SET_OOM (error);
1115 return FALSE;
1116 }
1117
1118 if (!_dbus_string_init (&cmdline))
1119 {
1120 _DBUS_SET_OOM (error);
1121 _dbus_string_free (&path);
1122 return FALSE;
1123 }
1124
1125 if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
1126 goto oom;
1127
1128 fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
1129 if (fd < 0)
1130 {
1131 dbus_set_error (error,
1132 _dbus_error_from_errno (errno),
1133 "Failed to open \"%s\": %s",
1134 _dbus_string_get_const_data (&path),
1135 _dbus_strerror (errno));
1136 goto fail;
1137 }
1138
1139 if (!_dbus_read (fd, &cmdline, max_len))
1140 {
1141 dbus_set_error (error,
1142 _dbus_error_from_errno (errno),
1143 "Failed to read from \"%s\": %s",
1144 _dbus_string_get_const_data (&path),
1145 _dbus_strerror (errno));
1146 goto fail;
1147 }
1148
1149 if (!_dbus_close (fd, error))
1150 goto fail;
1151
1152 string_squash_nonprintable (&cmdline);
1153
1154 if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
1155 goto oom;
1156
1157 _dbus_string_free (&cmdline);
1158 _dbus_string_free (&path);
1159 return TRUE;
1160 oom:
1161 _DBUS_SET_OOM (error);
1162 fail:
1163 _dbus_string_free (&cmdline);
1164 _dbus_string_free (&path);
1165 return FALSE;
1166 }
1167