"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "common.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Ident-2 - an Identity server for UNIX
3 * Copyright (C) 1998-2001 Michael Bacarella
4 * Copyright (C) 2003 Netgraft Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Please view the file README for program information.
21 *
22 * Common function definitions.
23 * Used without regulation by other modules
24 */
25
26 #include "ident2.h"
27
28 void *
29 xmalloc (size_t nb)
30 {
31 void *p = malloc (nb);
32
33 if (p == NULL) {
34 fprintf (stderr, "ident2: terminating on memory allocation error\n");
35 syslog (LOG_ERR, "error: memory allocation error");
36 exit (1);
37 }
38 return p;
39 }
40
41 /*
42 * a (skewed) fgets() that works on file descriptors
43 * the '\r' charecter is ignored
44 * returns the number of bytes written into the given
45 * buffer, including the terminating NUL
46 */
47 static int
48 _getl (int d, char *begin, u_short len)
49 {
50 char *p, *end;
51
52 end = &begin[len-1]; /* leave room for terminating NUL */
53 for (p = begin; p < end; ++p) {
54 if (read (d, p, 1) != 1)
55 break;
56 if (*p == '\n')
57 break;
58 if (*p == '\r')
59 p--; /* ignore \r */
60 }
61 *p++ = 0;
62 return p-begin;
63 }
64
65 /*
66 * this function is called directly as an inetd
67 * handler as well as a fork()ed into by the daemon
68 * service of the server..
69 */
70 void
71 child_service (int in, int out)
72 {
73 char buf[ID_BUF_SIZE];
74
75 signal (SIGALRM, exit);
76 alarm (Client_Timeout);
77
78 if (m_reduce_rights () == -1)
79 syslog (LOG_ERR, "error: cannot reduce self's rights "
80 "[m_reduce_rights()]");
81 else
82 while (_getl (in, buf, ID_BUF_SIZE) != 0)
83 nexus (out, buf);
84
85 close (in);
86 if (out != in)
87 close (out);
88 }
89
90
91 typedef struct cl_t {
92 int sd;
93 uid_t uid;
94 unsigned short lp, rp;
95 struct sockaddr_in laddr, raddr;
96 struct passwd *pw;
97 } cl_t;
98
99 /*
100 * send an ident formatted reply to client
101 */
102 static void
103 _clreply (cl_t *cl, char *rslt, char *info)
104 {
105 char buf[ID_BUF_SIZE+1];
106
107 buf[ID_BUF_SIZE] = 0;
108
109 snprintf (buf, ID_BUF_SIZE-1, "%d , %d : %s : %s\r\n",
110 cl->lp, cl->rp, rslt, info);
111 write (cl->sd, buf, strlen (buf));
112 }
113
114
115 static int
116 _check_noident (cl_t *cl)
117 {
118 char p[ID_BUF_SIZE+1];
119
120 p[ID_BUF_SIZE] = 0;
121
122 snprintf (p, ID_BUF_SIZE-1, "%s/%s", cl->pw->pw_dir, NOIDENT_FILE);
123
124 if (access (p, F_OK) == 0) {
125 _clreply (cl, "ERROR", "HIDDEN-USER");
126 syslog (LOG_INFO, "no reply to %s (query %d, %d) due to %s",
127 inet_ntoa (cl->raddr.sin_addr),
128 cl->lp, cl->rp, p);
129 return 0;
130 }
131 return -1;
132 }
133
134 static int
135 _check_user_ident (cl_t *cl)
136 {
137 FILE *fp;
138 int retval = -1;
139 char idfile[ID_BUF_SIZE+1];
140
141 idfile[ID_BUF_SIZE] = 0;
142 snprintf (idfile, ID_BUF_SIZE-1, "%s/%s",
143 cl->pw->pw_dir, User_Ident_File);
144
145 if (access (idfile, R_OK) == 0) {
146 if ((fp = fopen (idfile, "r")) != NULL) {
147 char *p, buf[4096];
148
149 memset (buf, 0, 4096);
150 fgets (buf, 4095, fp);
151 strtok (buf, "\r\n");
152
153 if ((p = strstr (buf, "ident "))) {
154 char rply[ID_BUF_SIZE+1];
155 rply[ID_BUF_SIZE] = 0;
156
157 snprintf (rply, ID_BUF_SIZE-1, "UNIX : %s", p+6);
158 _clreply (cl, "USERID", rply);
159
160 syslog (LOG_INFO, "sent reply `%s' to query %s "
161 "(%d, %d), uid = %d", p,
162 inet_ntoa (cl->raddr.sin_addr),
163 cl->lp, cl->rp, cl->uid);
164 retval = 0;
165 }
166 fclose (fp);
167 }
168 }
169 return retval;
170 }
171
172 /*
173 * handy for users who use an ip masqueraded setup that just
174 * want to friggin get on IRC and don't care what their ident
175 * is. Or if you want to annoy your IRC admins, because they
176 * totally deserve it.
177 */
178 static void
179 _send_random_reply (cl_t *cl)
180 {
181 char randstr[RAND_STRING_LENGTH+1];
182 char buf[ID_BUF_SIZE+1];
183 size_t i;
184
185 buf[ID_BUF_SIZE] = 0;
186
187 srand (time(NULL));
188 for (i = 0; i < RAND_STRING_LENGTH; i++) {
189 randstr[i] = rand();
190 while (randstr[i] > 'z')
191 randstr[i] -= 26;
192 while (randstr[i] < 'a')
193 randstr[i] += 26;
194 }
195 randstr[RAND_STRING_LENGTH] = 0;
196
197 snprintf (buf, ID_BUF_SIZE-1, "UNIX : %s", randstr);
198
199 _clreply (cl, "USERID", buf);
200 syslog (LOG_INFO, "sent random reply for query %s (%d, %d)",
201 inet_ntoa (cl->raddr.sin_addr), cl->lp, cl->rp);
202
203 return;
204 }
205 /*
206 * determines and collects client information
207 * and returns it in a neat and conveniant package
208 */
209 static cl_t *
210 _new_cl (int sd, char *line)
211 {
212 int uid, ssiz = sizeof (struct sockaddr);
213 cl_t *p, cl;
214 char *s;
215
216 cl.sd = sd;
217 cl.lp = cl.rp = 0;
218
219 if (!(s = strchr (line, ','))) {
220 _clreply (&cl, "ERROR", "INVALID-PORT");
221 return NULL;
222 }
223 *s = 0;
224 cl.lp = (u_short) atoi (line);
225 cl.rp = (u_short) atoi (s+1);
226
227 if (getsockname (sd, (struct sockaddr *)&cl.laddr, &ssiz) == -1) {
228 syslog (LOG_WARNING, "warning: getsockname(): %s\n",
229 strerror (errno));
230 _clreply (&cl, "ERROR", "UNKNOWN-ERROR");
231 return NULL;
232 }
233 if (getpeername (sd, (struct sockaddr *)&cl.raddr, &ssiz) == -1) {
234 syslog (LOG_WARNING, "warning: getpeername(): %s\n",
235 strerror (errno));
236 _clreply (&cl, "ERROR", "UNKNOWN-ERROR");
237 return NULL;
238 }
239
240 if (Reply_Always_Random == TRUE) {
241 _send_random_reply (&cl);
242 return NULL;
243 }
244
245 uid = m_get_uid (&cl.laddr.sin_addr, cl.lp, &cl.raddr.sin_addr, cl.rp);
246 if (uid == -1) {
247 syslog (LOG_WARNING, "warning: bad request: %d/%d, from %s",
248 cl.lp, cl.rp, inet_ntoa (cl.raddr.sin_addr));
249 _clreply (&cl, "ERROR", "NO-USER");
250 return NULL;
251 }
252 cl.uid = uid;
253
254 if ((cl.pw = getpwuid (cl.uid)) == NULL) {
255 syslog (LOG_ERR, "warning: cannot map %d to a username: %s "
256 "requested by query %s (%d, %d)", cl.uid,
257 strerror (errno), inet_ntoa (cl.raddr.sin_addr),
258 cl.lp, cl.rp);
259 _clreply (&cl, "ERROR", "UNKNOWN-ERROR");
260 return NULL;
261 }
262 p = xmalloc (sizeof (cl_t));
263 *p = cl;
264
265 return p;
266 }
267
268 /**
269 ** nexus
270 **
271 ** this is called by all service modes if
272 ** any reply is to be returned to the
273 ** client.
274 **/
275 void
276 nexus (int sd, char *line)
277 {
278 cl_t *cl;
279 char buf[ID_BUF_SIZE+1];
280
281 buf[ID_BUF_SIZE] = 0;
282
283 if ((cl = _new_cl (sd, line)) == NULL)
284 return;
285
286 /* if user configs are allowed, use the user's (if they
287 * have one, else just use the global config */
288 if (Allow_NOIDENT == TRUE)
289 if (!_check_noident (cl)) {
290 free (cl);
291 return;
292 }
293
294 if (Use_User_Ident == TRUE)
295 if (!_check_user_ident (cl)) {
296 free (cl);
297 return;
298 }
299
300 snprintf (buf, ID_BUF_SIZE-1, "UNIX : %s", cl->pw->pw_name);
301
302 _clreply (cl, "USERID", buf);
303 syslog (LOG_INFO, "sent reply `%s' to query %s "
304 "(%d, %d), uid = %d", cl->pw->pw_name,
305 inet_ntoa (cl->raddr.sin_addr), cl->lp,
306 cl->rp, cl->uid);
307
308 free (cl);
309 return;
310 }
311