utilvfs.c 9.6 KB

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