(linenum→info "unix/slp.c:2238")

dbus/1.0.2/dbus/dbus-sysdeps-util-unix.c

    1: /* -*- mode: C; c-file-style: "gnu" -*- */
    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22:  *
   23:  */
   24: #include "dbus-sysdeps.h"
   25: #include "dbus-sysdeps-unix.h"
   26: #include "dbus-internals.h"
   27: #include "dbus-protocol.h"
   28: #include "dbus-string.h"
   29: #define DBUS_USERDB_INCLUDES_PRIVATE 1
   30: #include "dbus-userdb.h"
   31: #include "dbus-test.h"
   32: 
   33: #include <sys/types.h>
   34: #include <stdlib.h>
   35: #include <string.h>
   36: #include <signal.h>
   37: #include <unistd.h>
   38: #include <stdio.h>
   39: #include <errno.h>
   40: #include <fcntl.h>
   41: #include <sys/stat.h>
   42: #include <grp.h>
   43: #include <sys/socket.h>
   44: #include <dirent.h>
   45: #include <sys/un.h>
   46: 
   47: #ifdef HAVE_SYS_SYSLIMITS_H
   48: #include <sys/syslimits.h>
   49: #endif
   50: 
   51: #ifndef O_BINARY
   52: #define O_BINARY 0
   53: #endif
   54: 
   55: /**
   56:  * @addtogroup DBusInternalsUtils
   57:  * @{
   58:  */
   59: 
   60: /**
   61:  * Does the chdir, fork, setsid, etc. to become a daemon process.
   62:  *
   63:  * @param pidfile #NULL, or pidfile to create
   64:  * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
   65:  * @param error return location for errors
   66:  * @returns #FALSE on failure
   67:  */
   68: dbus_bool_t
   69: _dbus_become_daemon (const DBusString *pidfile,
   70:                      int               print_pid_fd,
   71:                      DBusError        *error)
   72: {
   73:   const char *s;
   74:   pid_t child_pid;
   75:   int dev_null_fd;
   76: 
   77:   _dbus_verbose ("Becoming a daemon...\n");
   78: 
   79:   _dbus_verbose ("chdir to /\n");
   80:   if (chdir ("/") < 0)
   81:     {
   82:       dbus_set_error (error, DBUS_ERROR_FAILED,
   83:                       "Could not chdir() to root directory");
   84:       return FALSE;
   85:     }
   86: 
   87:   _dbus_verbose ("forking...\n");
   88:   switch ((child_pid = fork ()))
   89:     {
   90:     case -1:
   91:       _dbus_verbose ("fork failed\n");
   92:       dbus_set_error (error, _dbus_error_from_errno (errno),
   93:                       "Failed to fork daemon: %s", _dbus_strerror (errno));
   94:       return FALSE;
   95:       break;
   96: 
   97:     case 0:
   98:       _dbus_verbose ("in child, closing std file descriptors\n");
   99: 
  100:       /* silently ignore failures here, if someone
  101:        * doesn't have /dev/null we may as well try
  102:        * to continue anyhow
  103:        */
  104:       
  105:       dev_null_fd = open ("/dev/null", O_RDWR);
  106:       if (dev_null_fd >= 0)
  107:         {
  108:           dup2 (dev_null_fd, 0);
  109:           dup2 (dev_null_fd, 1);
  110:           
  111:           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
  112:           if (s == NULL || *s == '\0')
  113:             dup2 (dev_null_fd, 2);
  114:           else
  115:             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
  116:         }
  117: 
  118:       /* Get a predictable umask */
  119:       _dbus_verbose ("setting umask\n");
  120:       umask (022);
  121:       break;
  122: 
  123:     default:
  124:       if (pidfile)
  125:         {
  126:           _dbus_verbose ("parent writing pid file\n");
  127:           if (!_dbus_write_pid_file (pidfile,
  128:                                      child_pid,
  129:                                      error))
  130:             {
  131:               _dbus_verbose ("pid file write failed, killing child\n");
  132:               kill (child_pid, SIGTERM);
  133:               return FALSE;
  134:             }
  135:         }
  136: 
  137:       /* Write PID if requested */
  138:       if (print_pid_fd >= 0)
  139:         {
  140:           DBusString pid;
  141:           int bytes;
  142:           
  143:           if (!_dbus_string_init (&pid))
  144:             {
  145:               _DBUS_SET_OOM (error);
  146:               kill (child_pid, SIGTERM);
  147:               return FALSE;
  148:             }
  149:           
  150:           if (!_dbus_string_append_int (&pid, child_pid) ||
  151:               !_dbus_string_append (&pid, "\n"))
  152:             {
  153:               _dbus_string_free (&pid);
  154:               _DBUS_SET_OOM (error);
  155:               kill (child_pid, SIGTERM);
  156:               return FALSE;
  157:             }
  158:           
  159:           bytes = _dbus_string_get_length (&pid);
  160:           if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes)
  161:             {
  162:               dbus_set_error (error, DBUS_ERROR_FAILED,
  163:                               "Printing message bus PID: %s\n",
  164:                               _dbus_strerror (errno));
  165:               _dbus_string_free (&pid);
  166:               kill (child_pid, SIGTERM);
  167:               return FALSE;
  168:             }
  169:           
  170:           _dbus_string_free (&pid);
  171:         }
  172:       _dbus_verbose ("parent exiting\n");
  173:       _exit (0);
  174:       break;
  175:     }
  176: 
  177:   _dbus_verbose ("calling setsid()\n");
  178:   if (setsid () == -1)
  179:     _dbus_assert_not_reached ("setsid() failed");
  180:   
  181:   return TRUE;
  182: }
  183: 
  184: 
  185: /**
  186:  * Creates a file containing the process ID.
  187:  *
  188:  * @param filename the filename to write to
  189:  * @param pid our process ID
  190:  * @param error return location for errors
  191:  * @returns #FALSE on failure
  192:  */
  193: dbus_bool_t
  194: _dbus_write_pid_file (const DBusString *filename,
  195:                       unsigned long     pid,
  196:                       DBusError        *error)
  197: {
  198:   const char *cfilename;
  199:   int fd;
  200:   FILE *f;
  201: 
  202:   cfilename = _dbus_string_get_const_data (filename);
  203:   
  204:   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
  205:   
  206:   if (fd < 0)
  207:     {
  208:       dbus_set_error (error, _dbus_error_from_errno (errno),
  209:                       "Failed to open \"%s\": %s", cfilename,
  210:                       _dbus_strerror (errno));
  211:       return FALSE;
  212:     }
  213: 
  214:   if ((f = fdopen (fd, "w")) == NULL)
  215:     {
  216:       dbus_set_error (error, _dbus_error_from_errno (errno),
  217:                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
  218:       _dbus_close (fd, NULL);
  219:       return FALSE;
  220:     }
  221:   
  222:   if (fprintf (f, "%lu\n", pid) < 0)
  223:     {
  224:       dbus_set_error (error, _dbus_error_from_errno (errno),
  225:                       "Failed to write to \"%s\": %s", cfilename,
  226:                       _dbus_strerror (errno));
  227:       
  228:       fclose (f);
  229:       return FALSE;
  230:     }
  231: 
  232:   if (fclose (f) == EOF)
  233:     {
  234:       dbus_set_error (error, _dbus_error_from_errno (errno),
  235:                       "Failed to close \"%s\": %s", cfilename,
  236:                       _dbus_strerror (errno));
  237:       return FALSE;
  238:     }
  239:   
  240:   return TRUE;
  241: }
  242: 
  243: 
  244: /**
  245:  * Changes the user and group the bus is running as.
  246:  *
  247:  * @param uid the new user ID
  248:  * @param gid the new group ID
  249:  * @param error return location for errors
  250:  * @returns #FALSE on failure
  251:  */
  252: dbus_bool_t
  253: _dbus_change_identity  (dbus_uid_t     uid,
  254:                         dbus_gid_t     gid,
  255:                         DBusError     *error)
  256: {
  257:   /* setgroups() only works if we are a privileged process,
  258:    * so we don't return error on failure; the only possible
  259:    * failure is that we don't have perms to do it.
  260:    *
  261:    * not sure this is right, maybe if setuid()
  262:    * is going to work then setgroups() should also work.
  263:    */
  264:   if (setgroups (0, NULL) < 0)
  265:     _dbus_warn ("Failed to drop supplementary groups: %s\n",
  266:                 _dbus_strerror (errno));
  267:   
  268:   /* Set GID first, or the setuid may remove our permission
  269:    * to change the GID
  270:    */
  271:   if (setgid (gid) < 0)
  272:     {
  273:       dbus_set_error (error, _dbus_error_from_errno (errno),
  274:                       "Failed to set GID to %lu: %s", gid,
  275:                       _dbus_strerror (errno));
  276:       return FALSE;
  277:     }
  278:   
  279:   if (setuid (uid) < 0)
  280:     {
  281:       dbus_set_error (error, _dbus_error_from_errno (errno),
  282:                       "Failed to set UID to %lu: %s", uid,
  283:                       _dbus_strerror (errno));
  284:       return FALSE;
  285:     }
  286:   
  287:   return TRUE;
  288: }
  289: 
  290: /** Installs a UNIX signal handler
  291:  *
  292:  * @param sig the signal to handle
  293:  * @param handler the handler
  294:  */
  295: void
  296: _dbus_set_signal_handler (int               sig,
  297:                           DBusSignalHandler handler)
  298: {
  299:   struct sigaction act;
  300:   sigset_t empty_mask;
  301:   
  302:   sigemptyset (&empty_mask);
  303:   act.sa_handler = handler;
  304:   act.sa_mask    = empty_mask;
  305:   act.sa_flags   = 0;
  306:   sigaction (sig,  &act, NULL);
  307: }
  308: 
  309: 
  310: /**
  311:  * Removes a directory; Directory must be empty
  312:  * 
  313:  * @param filename directory filename
  314:  * @param error initialized error object
  315:  * @returns #TRUE on success
  316:  */
  317: dbus_bool_t
  318: _dbus_delete_directory (const DBusString *filename,
  319:                         DBusError        *error)
  320: {
  321:   const char *filename_c;
  322:   
  323:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  324: 
  325:   filename_c = _dbus_string_get_const_data (filename);
  326: 
  327:   if (rmdir (filename_c) != 0)
  328:     {
  329:       dbus_set_error (error, DBUS_ERROR_FAILED,
  330:                       "Failed to remove directory %s: %s\n",
  331:                       filename_c, _dbus_strerror (errno));
  332:       return FALSE;
  333:     }
  334:   
  335:   return TRUE;
  336: }
  337: 
  338: /** Checks if a file exists
  339: *
  340: * @param file full path to the file
  341: * @returns #TRUE if file exists
  342: */
  343: dbus_bool_t 
  344: _dbus_file_exists (const char *file)
  345: {
  346:   return (access (file, F_OK) == 0);
  347: }
  348: 
  349: /** Checks if user is at the console
  350: *
  351: * @param username user to check
  352: * @param error return location for errors
  353: * @returns #TRUE is the user is at the consolei and there are no errors
  354: */
  355: dbus_bool_t 
  356: _dbus_user_at_console (const char *username,
  357:                        DBusError  *error)
  358: {
  359: 
  360:   DBusString f;
  361:   dbus_bool_t result;
  362: 
  363:   result = FALSE;
  364:   if (!_dbus_string_init (&f))
  365:     {
  366:       _DBUS_SET_OOM (error);
  367:       return FALSE;
  368:     }
  369: 
  370:   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
  371:     {
  372:       _DBUS_SET_OOM (error);
  373:       goto out;
  374:     }
  375: 
  376: 
  377:   if (!_dbus_string_append (&f, username))
  378:     {
  379:       _DBUS_SET_OOM (error);
  380:       goto out;
  381:     }
  382: 
  383:   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
  384: 
  385:  out:
  386:   _dbus_string_free (&f);
  387: 
  388:   return result;
  389: }
  390: 
  391: 
  392: /**
  393:  * Checks whether the filename is an absolute path
  394:  *
  395:  * @param filename the filename
  396:  * @returns #TRUE if an absolute path
  397:  */
  398: dbus_bool_t
  399: _dbus_path_is_absolute (const DBusString *filename)
  400: {
  401:   if (_dbus_string_get_length (filename) > 0)
  402:     return _dbus_string_get_byte (filename, 0) == '/';
  403:   else
  404:     return FALSE;
  405: }
  406: 
  407: /**
  408:  * stat() wrapper.
  409:  *
  410:  * @param filename the filename to stat
  411:  * @param statbuf the stat info to fill in
  412:  * @param error return location for error
  413:  * @returns #FALSE if error was set
  414:  */
  415: dbus_bool_t
  416: _dbus_stat (const DBusString *filename,
  417:             DBusStat         *statbuf,
  418:             DBusError        *error)
  419: {
  420:   const char *filename_c;
  421:   struct stat sb;
  422: 
  423:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  424:   
  425:   filename_c = _dbus_string_get_const_data (filename);
  426: 
  427:   if (stat (filename_c, &sb) < 0)
  428:     {
  429:       dbus_set_error (error, _dbus_error_from_errno (errno),
  430:                       "%s", _dbus_strerror (errno));
  431:       return FALSE;
  432:     }
  433: 
  434:   statbuf->mode = sb.st_mode;
  435:   statbuf->nlink = sb.st_nlink;
  436:   statbuf->uid = sb.st_uid;
  437:   statbuf->gid = sb.st_gid;
  438:   statbuf->size = sb.st_size;
  439:   statbuf->atime = sb.st_atime;
  440:   statbuf->mtime = sb.st_mtime;
  441:   statbuf->ctime = sb.st_ctime;
  442: 
  443:   return TRUE;
  444: }
  445: 
  446: 
  447: /**
  448:  * Internals of directory iterator
  449:  */
  450: struct DBusDirIter
  451: {
  452:   DIR *d; /**< The DIR* from opendir() */
  453:   
  454: };
  455: 
  456: /**
  457:  * Open a directory to iterate over.
  458:  *
  459:  * @param filename the directory name
  460:  * @param error exception return object or #NULL
  461:  * @returns new iterator, or #NULL on error
  462:  */
  463: DBusDirIter*
  464: _dbus_directory_open (const DBusString *filename,
  465:                       DBusError        *error)
  466: {
  467:   DIR *d;
  468:   DBusDirIter *iter;
  469:   const char *filename_c;
  470: 
  471:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  472:   
  473:   filename_c = _dbus_string_get_const_data (filename);
  474: 
  475:   d = opendir (filename_c);
  476:   if (d == NULL)
  477:     {
  478:       dbus_set_error (error, _dbus_error_from_errno (errno),
  479:                       "Failed to read directory \"%s\": %s",
  480:                       filename_c,
  481:                       _dbus_strerror (errno));
  482:       return NULL;
  483:     }
  484:   iter = dbus_new0 (DBusDirIter, 1);
  485:   if (iter == NULL)
  486:     {
  487:       closedir (d);
  488:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
  489:                       "Could not allocate memory for directory iterator");
  490:       return NULL;
  491:     }
  492: 
  493:   iter->d = d;
  494: 
  495:   return iter;
  496: }
  497: 
  498: /* Calculate the required buffer size (in bytes) for directory
  499:  * entries read from the given directory handle.  Return -1 if this
  500:  * this cannot be done. 
  501:  *
  502:  * If you use autoconf, include fpathconf and dirfd in your
  503:  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
  504:  * and use them where available.
  505:  */
  506: static dbus_bool_t
  507: dirent_buf_size(DIR * dirp, size_t *size)
  508: {
  509:  long name_max;
  510: #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
  511: #      if defined(HAVE_DIRFD)
  512:           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
  513: #      elif defined(HAVE_DDFD)
  514:           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
  515: #      else
  516:           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
  517: #      endif /* HAVE_DIRFD */
  518:      if (name_max == -1)
  519: #           if defined(NAME_MAX)
  520:              name_max = NAME_MAX;
  521: #           else
  522:              return FALSE;
  523: #           endif
  524: #   elif defined(MAXNAMELEN)
  525:      name_max = MAXNAMELEN;
  526: #   else
  527: #       if defined(NAME_MAX)
  528:          name_max = NAME_MAX;
  529: #       else
  530: #           error "buffer size for readdir_r cannot be determined"
  531: #       endif
  532: #   endif
  533:   if (size)
  534:     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
  535:   else
  536:     return FALSE;
  537: 
  538:   return TRUE;
  539: }
  540: 
  541: /**
  542:  * Get next file in the directory. Will not return "." or ".."  on
  543:  * UNIX. If an error occurs, the contents of "filename" are
  544:  * undefined. The error is never set if the function succeeds.
  545:  *
  546:  * @param iter the iterator
  547:  * @param filename string to be set to the next file in the dir
  548:  * @param error return location for error
  549:  * @returns #TRUE if filename was filled in with a new filename
  550:  */
  551: dbus_bool_t
  552: _dbus_directory_get_next_file (DBusDirIter      *iter,
  553:                                DBusString       *filename,
  554:                                DBusError        *error)
  555: {
  556:   struct dirent *d, *ent;
  557:   size_t buf_size;
  558:   int err;
  559: 
  560:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  561:  
  562:   if (!dirent_buf_size (iter->d, &buf_size))
  563:     {
  564:       dbus_set_error (error, DBUS_ERROR_FAILED,
  565:                       "Can't calculate buffer size when reading directory");
  566:       return FALSE;
  567:     }
  568: 
  569:   d = (struct dirent *)dbus_malloc (buf_size);
  570:   if (!d)
  571:     {
  572:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
  573:                       "No memory to read directory entry");
  574:       return FALSE;
  575:     }
  576: 
  577:  again:
  578:   err = readdir_r (iter->d, d, &ent);
  579:   if (err || !ent)
  580:     {
  581:       if (err != 0)
  582:         dbus_set_error (error,
  583:                         _dbus_error_from_errno (err),
  584:                         "%s", _dbus_strerror (err));
  585: 
  586:       dbus_free (d);
  587:       return FALSE;
  588:     }
  589:   else if (ent->d_name[