root/lib/vfs/utilvfs.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. vfs_get_local_username
  2. vfs_finduid
  3. vfs_findgid
  4. vfs_mkstemps
  5. vfs_url_split
  6. vfs_die
  7. vfs_get_password

   1 /*
   2    Utilities for VFS modules.
   3 
   4    Copyright (C) 1988-2021
   5    Free Software Foundation, Inc.
   6 
   7    Copyright (C) 1995, 1996 Miguel de Icaza
   8 
   9    This file is part of the Midnight Commander.
  10 
  11    The Midnight Commander is free software: you can redistribute it
  12    and/or modify it under the terms of the GNU General Public License as
  13    published by the Free Software Foundation, either version 3 of the License,
  14    or (at your option) any later version.
  15 
  16    The Midnight Commander is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23  */
  24 
  25 /**
  26  * \file
  27  * \brief Source: Utilities for VFS modules
  28  * \author Miguel de Icaza
  29  * \date 1995, 1996
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <ctype.h>
  35 #include <sys/types.h>
  36 #include <pwd.h>
  37 #include <grp.h>
  38 #include <stdlib.h>
  39 #include <string.h>
  40 
  41 #include "lib/global.h"
  42 #include "lib/unixcompat.h"
  43 #include "lib/util.h"           /* mc_mkstemps() */
  44 #include "lib/widget.h"         /* message() */
  45 #include "lib/strutil.h"        /* INVALID_CONV */
  46 
  47 #include "vfs.h"
  48 #include "utilvfs.h"
  49 
  50 /*** global variables ****************************************************************************/
  51 
  52 /*** file scope macro definitions ****************************************************************/
  53 
  54 #ifndef TUNMLEN
  55 #define TUNMLEN 256
  56 #endif
  57 #ifndef TGNMLEN
  58 #define TGNMLEN 256
  59 #endif
  60 
  61 #define MC_HISTORY_VFS_PASSWORD       "mc.vfs.password"
  62 
  63 /*
  64  * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
  65  */
  66 #define GUID_DEFAULT_CONST -993
  67 
  68 /*** file scope type declarations ****************************************************************/
  69 
  70 /*** file scope variables ************************************************************************/
  71 
  72 /*** file scope functions ************************************************************************/
  73 /* --------------------------------------------------------------------------------------------- */
  74 
  75 
  76 /* --------------------------------------------------------------------------------------------- */
  77 /*** public functions ****************************************************************************/
  78 /* --------------------------------------------------------------------------------------------- */
  79 /** Get current username
  80  *
  81  * @return g_malloc()ed string with the name of the currently logged in
  82  *         user ("anonymous" if uid is not registered in the system)
  83  */
  84 
  85 char *
  86 vfs_get_local_username (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  87 {
  88     struct passwd *p_i;
  89 
  90     p_i = getpwuid (geteuid ());
  91 
  92     return (p_i && p_i->pw_name) ? g_strdup (p_i->pw_name) : g_strdup ("anonymous");    /* Unknown UID, strange */
  93 }
  94 
  95 /* --------------------------------------------------------------------------------------------- */
  96 /**
  97  * Look up a user or group name from a uid/gid, maintaining a cache.
  98  * FIXME, for now it's a one-entry cache.
  99  * This file should be modified for non-unix systems to do something
 100  * reasonable.
 101  */
 102 
 103 /* --------------------------------------------------------------------------------------------- */
 104 
 105 int
 106 vfs_finduid (const char *uname)
     /* [previous][next][first][last][top][bottom][index][help]  */
 107 {
 108     static int saveuid = GUID_DEFAULT_CONST;
 109     static char saveuname[TUNMLEN] = "\0";
 110 
 111     size_t uname_len;
 112 
 113     uname_len = strlen (uname);
 114 
 115     if (uname[0] != saveuname[0]        /* Quick test w/o proc call */
 116         || strncmp (uname, saveuname, MIN (uname_len, TUNMLEN - 1)) != 0)
 117     {
 118         struct passwd *pw;
 119 
 120         g_strlcpy (saveuname, uname, TUNMLEN);
 121         pw = getpwnam (uname);
 122         if (pw)
 123         {
 124             saveuid = pw->pw_uid;
 125         }
 126         else
 127         {
 128             static int my_uid = GUID_DEFAULT_CONST;
 129 
 130             if (my_uid < 0)
 131                 my_uid = getuid ();
 132 
 133             saveuid = my_uid;
 134         }
 135     }
 136     return saveuid;
 137 }
 138 
 139 /* --------------------------------------------------------------------------------------------- */
 140 
 141 int
 142 vfs_findgid (const char *gname)
     /* [previous][next][first][last][top][bottom][index][help]  */
 143 {
 144     static int savegid = GUID_DEFAULT_CONST;
 145     static char savegname[TGNMLEN] = "\0";
 146 
 147     size_t gname_len;
 148 
 149     gname_len = strlen (gname);
 150 
 151     if (gname[0] != savegname[0]        /* Quick test w/o proc call */
 152         || strncmp (gname, savegname, MIN (gname_len, TGNMLEN - 1)) != 0)
 153     {
 154         struct group *gr;
 155 
 156         g_strlcpy (savegname, gname, TGNMLEN);
 157         gr = getgrnam (gname);
 158         if (gr)
 159         {
 160             savegid = gr->gr_gid;
 161         }
 162         else
 163         {
 164             static int my_gid = GUID_DEFAULT_CONST;
 165 
 166             if (my_gid < 0)
 167                 my_gid = getgid ();
 168 
 169             savegid = my_gid;
 170         }
 171     }
 172     return savegid;
 173 }
 174 
 175 /* --------------------------------------------------------------------------------------------- */
 176 /**
 177  * Create a temporary file with a name resembling the original.
 178  * This is needed e.g. for local copies requested by extfs.
 179  * Some extfs scripts may look at the extension.
 180  * We also protect stupid scripts agains dangerous names.
 181  */
 182 
 183 int
 184 vfs_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *param_basename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 185 {
 186     const char *p;
 187     GString *suffix;
 188     int shift;
 189     int fd;
 190 
 191     /* Strip directories */
 192     p = strrchr (param_basename, PATH_SEP);
 193     if (p == NULL)
 194         p = param_basename;
 195     else
 196         p++;
 197 
 198     /* Protection against very long names */
 199     shift = strlen (p) - (MC_MAXPATHLEN - 16);
 200     if (shift > 0)
 201         p += shift;
 202 
 203     suffix = g_string_sized_new (32);
 204 
 205     /* Protection against unusual characters */
 206     for (; *p != '\0' && *p != '#'; p++)
 207         if (strchr (".-_@", *p) != NULL || g_ascii_isalnum (*p))
 208             g_string_append_c (suffix, *p);
 209 
 210     fd = mc_mkstemps (pname_vpath, prefix, suffix->str);
 211     g_string_free (suffix, TRUE);
 212 
 213     return fd;
 214 }
 215 
 216 /* --------------------------------------------------------------------------------------------- */
 217 /**  Extract the hostname and username from the path
 218  *
 219  * Format of the path is [user@]hostname:port/remote-dir, e.g.:
 220  *
 221  * ftp://sunsite.unc.edu/pub/linux
 222  * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
 223  * ftp://tsx-11.mit.edu:8192/
 224  * ftp://joe@foo.edu:11321/private
 225  * ftp://joe:password@foo.se
 226  *
 227  * @param path is an input string to be parsed
 228  * @param default_port is an input default port
 229  * @param flags are parsing modifier flags (@see vfs_url_flags_t)
 230  *
 231  * @return g_malloc()ed url info.
 232  *         If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
 233  *         is not set, then the current login name is supplied.
 234  *         Return value is a g_malloc()ed structure with the pathname relative to the
 235  *         host.
 236  */
 237 
 238 vfs_path_element_t *
 239 vfs_url_split (const char *path, int default_port, vfs_url_flags_t flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 240 {
 241     vfs_path_element_t *path_element;
 242 
 243     char *pcopy;
 244     size_t pcopy_len;
 245     const char *pend;
 246     char *colon, *at, *rest;
 247 
 248     path_element = g_new0 (vfs_path_element_t, 1);
 249     path_element->port = default_port;
 250 
 251     pcopy_len = strlen (path);
 252     pcopy = g_strndup (path, pcopy_len);
 253     pend = pcopy + pcopy_len;
 254 
 255     if ((flags & URL_NOSLASH) == 0)
 256     {
 257         char *dir = pcopy;
 258 
 259         /* locate path component */
 260         while (!IS_PATH_SEP (*dir) && *dir != '\0')
 261             dir++;
 262         if (*dir == '\0')
 263             path_element->path = g_strdup (PATH_SEP_STR);
 264         else
 265         {
 266             path_element->path = g_strndup (dir, pcopy_len - (size_t) (dir - pcopy));
 267             *dir = '\0';
 268         }
 269     }
 270 
 271     /* search for any possible user */
 272     at = strrchr (pcopy, '@');
 273 
 274     /* We have a username */
 275     if (at == NULL)
 276         rest = pcopy;
 277     else
 278     {
 279         char *inner_colon;
 280 
 281         *at = '\0';
 282         inner_colon = strchr (pcopy, ':');
 283         if (inner_colon != NULL)
 284         {
 285             *inner_colon = '\0';
 286             inner_colon++;
 287             path_element->password = g_strdup (inner_colon);
 288         }
 289 
 290         if (*pcopy != '\0')
 291             path_element->user = g_strdup (pcopy);
 292 
 293         if (pend == at + 1)
 294             rest = at;
 295         else
 296             rest = at + 1;
 297     }
 298 
 299     if ((flags & URL_USE_ANONYMOUS) == 0)
 300     {
 301         g_free (path_element->user);
 302         path_element->user = vfs_get_local_username ();
 303     }
 304     /* Check if the host comes with a port spec, if so, chop it */
 305     if (*rest != '[')
 306         colon = strchr (rest, ':');
 307     else
 308     {
 309         colon = strchr (++rest, ']');
 310         if (colon != NULL)
 311         {
 312             colon[0] = '\0';
 313             colon[1] = '\0';
 314             colon++;
 315         }
 316         else
 317         {
 318             vfs_path_element_free (path_element);
 319             g_free (pcopy);
 320             return NULL;
 321         }
 322     }
 323 
 324     if (colon != NULL)
 325     {
 326         *colon = '\0';
 327         /* cppcheck-suppress invalidscanf */
 328         if (sscanf (colon + 1, "%d", &path_element->port) == 1)
 329         {
 330             if (path_element->port <= 0 || path_element->port >= 65536)
 331                 path_element->port = default_port;
 332         }
 333         else
 334             while (*(++colon) != '\0')
 335             {
 336                 switch (*colon)
 337                 {
 338                 case 'C':
 339                     path_element->port = 1;
 340                     break;
 341                 case 'r':
 342                     path_element->port = 2;
 343                     break;
 344                 default:
 345                     break;
 346                 }
 347             }
 348     }
 349 
 350     path_element->host = g_strdup (rest);
 351     g_free (pcopy);
 352 #ifdef HAVE_CHARSET
 353     path_element->dir.converter = INVALID_CONV;
 354 #endif
 355 
 356     return path_element;
 357 }
 358 
 359 /* --------------------------------------------------------------------------------------------- */
 360 
 361 void __attribute__ ((noreturn)) vfs_die (const char *m)
     /* [previous][next][first][last][top][bottom][index][help]  */
 362 {
 363     message (D_ERROR, _("Internal error:"), "%s", m);
 364     exit (EXIT_FAILURE);
 365 }
 366 
 367 /* --------------------------------------------------------------------------------------------- */
 368 
 369 char *
 370 vfs_get_password (const char *msg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 371 {
 372     return input_dialog (msg, _("Password:"), MC_HISTORY_VFS_PASSWORD, INPUT_PASSWORD,
 373                          INPUT_COMPLETE_NONE);
 374 }
 375 
 376 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */