utilvfs.c 9.5 KB

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