utilvfs.c 9.4 KB

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