summaryrefslogtreecommitdiff
path: root/ftpfs/host.c
blob: cd6fd4c0fc79df185f30d5cedac3bec0860314a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Server lookup

   Copyright (C) 1997 Free Software Foundation, Inc.
   Written by Miles Bader <miles@gnu.ai.mit.edu>
   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <ftpconn.h>

/* Split the server-specification string SERVER into its components: a
   hostname (returned in HOST), username (USER), and password (PASSWD).  */
static error_t
split_server_name (const char *server, char **host, char **user, char **passwd)
{
  size_t plim;
  const char *p = server, *sep;

  *host = 0;
  *user = 0;
  *passwd = 0;

  /* Extract the hostname; syntax is either `HOST:...', `...@HOST', or just
     HOST if there are no user parameters specified.  */
  sep = strrchr (p, '@');
  if (sep)
    /* ...@HOST */
    {
      *host = strdup (sep + 1);
      if (! *host)
	return ENOMEM;
      plim = sep - server;
    }
  else
    {
      sep = strchr (server, ':');
      if (sep)
	/* HOST:... */
	{
	  *host = strndup (server, sep - server);
	  if (! *host)
	    return ENOMEM;
	  p = sep + 1;
	  plim = strlen (p);
	}
      else
	/* Just HOST */
	{
	  *host = strdup (server);
	  if (! *host)
	    return ENOMEM;
	  return 0;
	}
    }

  /* Now P...P+PLIM contains any user parameters for HOST.  */
  sep = memchr (p, ':', plim);
  if (sep)
    /* USERNAME:PASSWD */
    {
      *user = strndup (p, sep - p);
      *passwd = strndup (sep + 1, plim - (sep + 1 - p));
      if (!*user || !*passwd)
	{
	  if (*user)
	    free (*user);
	  if (*passwd)
	    free (*passwd);
	  free (*host);
	  return ENOMEM;
	}
    }
  else
    /* Just USERNAME */
    {
      *user = strndup (p, plim);
      if (! *user)
	free (*user);
    }

  return 0;
}

/*  */
error_t
lookup_server (const char *server, struct ftp_conn_params **params, int *h_err)
{
  char hostent_data[2048];	/* XXX what size should this be???? */
  struct hostent _he, *he;
  char *host, *user, *passwd;
  error_t err = split_server_name (server, &host, &user, &passwd);

  if (err)
    return err;

  /* We didn't find a pre-existing host entry.  Make a new one.  Note that
     since we don't lock anything while making up our new structure, another
     thread could have inserted a duplicate entry for the same host name, but
     this isn't really a problem, just annoying.  */

  if (gethostbyname_r (host, &_he, hostent_data, sizeof hostent_data,
		       &he, h_err) == 0)
    {
      *params = malloc (sizeof (struct ftp_conn_params));
      if (! *params)
	err = ENOMEM;
      else
	{
	  (*params)->addr = malloc (he->h_length);
	  if (! (*params)->addr)
	    {
	      free (*params);
	      err = ENOMEM;
	    }
	  else
	    {
	      bcopy (he->h_addr_list[0], (*params)->addr, he->h_length);
	      (*params)->addr_len = he->h_length;
	      (*params)->addr_type = he->h_addrtype;
	      (*params)->user = user;
	      (*params)->pass = passwd;
	      (*params)->acct = 0;
	    }
	}
    }
  else
    err = EINVAL;

  free (host);

  if (err)
    {
      free (user);
      free (passwd);
    }

  return err;
}