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