1 /*
2 ** support.c - Miscellaneous support functions.
3 **
4 ** Copyright (c) 1997-2000 Peter Eriksson <pen@lysator.liu.se>
5 **
6 ** This program is free software; you can redistribute it and/or
7 ** modify it as you wish - as long as you don't claim that you wrote
8 ** it.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 */
14
15 #define PLIB_IN_SUPPORT_C
16
17 #include "plib/config.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <syslog.h>
25 #include <pwd.h>
26 #include <grp.h>
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32
33 #ifdef HAVE_UNAME
34 #include <sys/utsname.h>
35 #endif
36
37 #include "plib/threads.h"
38 #include "plib/safestr.h"
39 #include "plib/support.h"
40 #include "plib/sockaddr.h"
41
42
43 /*
44 ** Get the OS name and version number
45 */
46 char *
osinfo_get(char * buf,int bufsize)47 osinfo_get(char *buf,
48 int bufsize)
49 {
50 #ifdef HAVE_UNAME
51 struct utsname ub;
52
53 if (uname(&ub) < 0)
54 return NULL;
55
56 #ifndef _AIX
57 s_snprintf(buf, bufsize, "%s %s", ub.sysname, ub.release);
58 #else
59 s_snprintf(buf, bufsize, "%s %s.%s", ub.sysname, ub.version, ub.release);
60 #endif
61 #else
62 if (strlcpy(buf, "<unknown>", bufsize) >= bufsize)
63 return NULL;
64 #endif
65
66 return buf;
67 }
68
69
70
71 /*
72 ** Classify what type of socket the file descript "fd" is
73 */
74 int
socktype(int fd)75 socktype(int fd)
76 {
77 struct sockaddr_gen remote_sin, local_sin;
78 socklen_t len;
79 int code;
80
81
82 /* Try to get the local socket adress and port number */
83 len = sizeof(local_sin);
84 code = getsockname(fd, (struct sockaddr *) &local_sin, &len);
85 if (code < 0)
86 {
87 if (errno == ENOTSOCK || errno == EINVAL)
88 /* Not a TCP/IP socket */
89 return SOCKTYPE_NOTSOCKET;
90 else
91 return -1;
92 }
93
94
95 /* Try to get the remote socket adress and port number */
96 len = sizeof(remote_sin);
97 code = getpeername(fd, (struct sockaddr *) &remote_sin, &len);
98 if (code < 0)
99 {
100 if (errno == ENOTCONN)
101 /* Locally bound TCP socket, awaiting connections */
102 return SOCKTYPE_LISTEN;
103 else
104 return -1;
105 }
106
107 /* Established TCP connection */
108 return SOCKTYPE_CONNECTED;
109 }
110
111
112
113 #ifndef HAVE_STRERROR
114 char *
strerror(int err)115 strerror(int err)
116 {
117 #ifdef NEED_SYS_ERRLIST
118 extern int sys_nerr;
119 extern char *sys_errlist[];
120 #endif
121 static char errbuf[64];
122
123 if (err < 0 || err >= sys_nerr)
124 {
125 if (s_snprintf(errbuf, sizeof(errbuf), "#%d", err) < 0)
126 return "<unknown>";
127
128 return errbuf;
129 }
130 else
131 return sys_errlist[err];
132 }
133 #endif
134
135
136
137
138 #if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R)
139 static pthread_mutex_t pwd_lock;
140 static pthread_once_t pwd_once = PTHREAD_ONCE_INIT;
141
142 static void
pwd_lock_init(void)143 pwd_lock_init(void)
144 {
145 pthread_mutex_init(&pwd_lock, NULL);
146 }
147
148 static char *
strcopy(const char * str,char ** buf,size_t * avail)149 strcopy(const char *str, char **buf, size_t *avail)
150 {
151 char *start;
152 size_t len;
153
154
155 if (str == NULL)
156 return NULL;
157
158 len = strlen(str)+1;
159 if (len > *avail)
160 return NULL;
161
162 start = *buf;
163
164 memcpy(*buf, str, len);
165 *avail -= len;
166 *buf += len;
167
168 return start;
169 }
170 #endif
171
172
173 int
s_getpwnam_r(const char * name,struct passwd * pwd,char * buffer,size_t bufsize,struct passwd ** result)174 s_getpwnam_r(const char *name,
175 struct passwd *pwd,
176 char *buffer, size_t bufsize,
177 struct passwd **result)
178 {
179 #ifdef HAVE_GETPWNAM_R
180 int code;
181
182
183 memset(pwd, 0, sizeof(*pwd));
184 memset(buffer, 0, bufsize);
185
186 #ifdef HAVE_UI_GETPW /* Unix International / Solaris / UnixWare */
187
188 while ((*result = getpwnam_r(name, pwd, buffer, bufsize)) == NULL &&
189 errno == EINTR)
190 ;
191
192 if (*result == NULL)
193 code = errno;
194 else
195 code = 0;
196
197 #elif HAVE_DCE_GETPW /* DCE/CMA */
198
199 while ((code = getpwnam_r(name, pwd, buffer, bufsize)) != 0 &&
200 errno == EINTR)
201 ;
202 if (code == 0)
203 *result = pwd;
204 else
205 code = errno;
206
207 #else /* Posix version */
208
209 while ((code = getpwnam_r(name, pwd, buffer, bufsize, result)) == EINTR)
210 ;
211
212 #endif
213
214 return code;
215
216 #else /* No reentrant getpw*_r calls available */
217
218 struct passwd *pp;
219
220 pthread_once(&pwd_once, pwd_lock_init);
221
222 pthread_mutex_lock(&pwd_lock);
223
224 pp = getpwnam(name);
225 if (pp == NULL)
226 {
227 pthread_mutex_unlock(&pwd_lock);
228 *result = NULL;
229 return -1;
230 }
231
232 memset(pwd, 0, sizeof(*pwd));
233
234 pwd->pw_name = strcopy(pp->pw_name, &buffer, &bufsize);
235 pwd->pw_passwd = strcopy(pp->pw_passwd, &buffer, &bufsize);
236 pwd->pw_uid = pp->pw_uid;
237 pwd->pw_gid = pp->pw_gid;
238 pwd->pw_gecos = strcopy(pp->pw_gecos, &buffer, &bufsize);
239 pwd->pw_dir = strcopy(pp->pw_dir, &buffer, &bufsize);
240 pwd->pw_shell = strcopy(pp->pw_shell, &buffer, &bufsize);
241
242 *result = pwd;
243
244 pthread_mutex_unlock(&pwd_lock);
245 return 0;
246 #endif
247 }
248
249
250
251 int
s_getpwuid_r(uid_t uid,struct passwd * pwd,char * buffer,size_t bufsize,struct passwd ** result)252 s_getpwuid_r(uid_t uid,
253 struct passwd *pwd,
254 char *buffer, size_t bufsize,
255 struct passwd **result)
256 {
257 #ifdef HAVE_GETPWUID_R
258 int code;
259
260
261 memset(pwd, 0, sizeof(*pwd));
262 memset(buffer, 0, bufsize);
263
264 #ifdef HAVE_UI_GETPW /* Unix International / Solaris / UnixWare */
265
266 while ((*result = getpwuid_r(uid, pwd, buffer, bufsize)) == NULL &&
267 errno == EINTR)
268 ;
269
270 if (*result == NULL)
271 code = errno;
272 else
273 code = 0;
274
275 #elif HAVE_DCE_GETPW /* DCE/CMA */
276
277 while ((code = getpwuid_r(uid, pwd, buffer, bufsize)) != 0 &&
278 errno == EINTR)
279 ;
280 if (code == 0)
281 *result = pwd;
282 else
283 code = errno;
284
285 #else /* Posix version */
286
287 while ((code = getpwuid_r(uid, pwd, buffer, bufsize, result)) == EINTR)
288 ;
289
290 #endif
291
292 return code;
293
294 #else
295 struct passwd *pp;
296
297 pthread_once(&pwd_once, pwd_lock_init);
298 pthread_mutex_lock(&pwd_lock);
299
300 pp = getpwuid(uid);
301 if (pp == NULL)
302 {
303 pthread_mutex_unlock(&pwd_lock);
304
305 *result = NULL;
306 return -1;
307 }
308
309 memset(pwd, 0, sizeof(*pwd));
310
311 pwd->pw_name = strcopy(pp->pw_name, &buffer, &bufsize);
312 pwd->pw_passwd = strcopy(pp->pw_passwd, &buffer, &bufsize);
313 pwd->pw_uid = pp->pw_uid;
314 pwd->pw_gid = pp->pw_gid;
315 pwd->pw_gecos = strcopy(pp->pw_gecos, &buffer, &bufsize);
316 pwd->pw_dir = strcopy(pp->pw_dir, &buffer, &bufsize);
317 pwd->pw_shell = strcopy(pp->pw_shell, &buffer, &bufsize);
318
319 *result = pwd;
320
321 pthread_mutex_unlock(&pwd_lock);
322
323 return 0;
324 #endif
325 }
326
327
328 int
s_getgrgid_r(gid_t gid,struct group * grp,char * buffer,size_t bufsize,struct group ** result)329 s_getgrgid_r(gid_t gid,
330 struct group *grp,
331 char *buffer, size_t bufsize,
332 struct group **result)
333 {
334 #ifdef HAVE_GETPWUID_R
335 int code;
336
337
338 memset(grp, 0, sizeof(*grp));
339 memset(buffer, 0, bufsize);
340
341 #ifdef HAVE_UI_GETPW /* Unix International / Solaris / UnixWare */
342
343 while ((*result = getgrgid_r(gid, grp, buffer, bufsize)) == NULL &&
344 errno == EINTR)
345 ;
346
347 if (*result == NULL)
348 code = errno;
349 else
350 code = 0;
351
352 #elif HAVE_DCE_GETPW /* DCE/CMA */
353
354 while ((code = getgrgid_r(gid, grp, buffer, bufsize)) != 0 &&
355 errno == EINTR)
356 ;
357 if (code == 0)
358 *result = pwd;
359 else
360 code = errno;
361
362 #else /* Posix version */
363
364 while ((code = getgrgid_r(gid, grp, buffer, bufsize, result)) == EINTR)
365 ;
366
367 #endif
368
369 return code;
370
371 #else
372 pthread_once_t grp_once;
373 pthread_mutex_t grp_lock;
374 struct group *gp;
375 int i, len;
376
377
378 pthread_once(&grp_once, NULL);
379 pthread_mutex_lock(&grp_lock);
380
381 gp = getgrgid(gid);
382 if (gp == NULL)
383 {
384 pthread_mutex_unlock(&grp_lock);
385
386 *result = NULL;
387 return -1;
388 }
389
390 memset(grp, 0, sizeof(*grp));
391
392 grp->gr_name = strcopy(gp->gr_name, &buffer, &bufsize);
393 grp->gr_passwd = strcopy(gp->gr_passwd, &buffer, &bufsize);
394 grp->gr_gid = gp->gr_gid;
395
396 for (i = 0; gp->gr_mem[i]; ++i)
397 ;
398 len = i;
399
400 grp->gr_mem = a_malloc(sizeof(char *) * (len+1));
401 for (i = 0; i < len; ++i)
402 grp->gr_mem[i] = strcopy(gp->gr_mem[i], &buffer, &bufsize);
403 grp->gr_mem[i] = NULL;
404
405 *result = grp;
406
407 pthread_mutex_unlock(&grp_lock);
408
409 return 0;
410 #endif
411 }
412
413 int
s_getgrnam_r(const char * name,struct group * grp,char * buffer,size_t bufsize,struct group ** result)414 s_getgrnam_r(const char *name,
415 struct group *grp,
416 char *buffer, size_t bufsize,
417 struct group **result)
418 {
419 #ifdef HAVE_GETPWNAM_R
420 int code;
421
422
423 memset(grp, 0, sizeof(*grp));
424 memset(buffer, 0, bufsize);
425
426 #ifdef HAVE_UI_GETPW /* Unix International / Solaris / UnixWare */
427
428 while ((*result = getgrname_r(name, grp, buffer, bufsize)) == NULL &&
429 errno == EINTR)
430 ;
431
432 if (*result == NULL)
433 code = errno;
434 else
435 code = 0;
436
437 #elif HAVE_DCE_GETPW /* DCE/CMA */
438
439 while ((code = getgrnam_r(name, grp, buffer, bufsize)) != 0 &&
440 errno == EINTR)
441 ;
442 if (code == 0)
443 *result = pwd;
444 else
445 code = errno;
446
447 #else /* Posix version */
448
449 while ((code = getgrnam_r(name, grp, buffer, bufsize, result)) == EINTR)
450 ;
451
452 #endif
453
454 return code;
455
456 #else
457 pthread_once_t grp_once;
458 pthread_mutex_t grp_lock;
459 struct group *gp;
460 int i, len;
461
462
463 pthread_once(&grp_once, NULL);
464 pthread_mutex_lock(&grp_lock);
465
466 gp = getgrnam(name);
467 if (gp == NULL)
468 {
469 pthread_mutex_unlock(&grp_lock);
470
471 *result = NULL;
472 return -1;
473 }
474
475 memset(grp, 0, sizeof(*grp));
476
477 grp->gr_name = strcopy(gp->gr_name, &buffer, &bufsize);
478 grp->gr_passwd = strcopy(gp->gr_passwd, &buffer, &bufsize);
479 grp->gr_gid = gp->gr_gid;
480
481 for (i = 0; gp->gr_mem[i]; ++i)
482 ;
483 len = i;
484
485 grp->gr_mem = a_malloc(sizeof(char *) * (len+1));
486 for (i = 0; i < len; ++i)
487 grp->gr_mem[i] = strcopy(gp->gr_mem[i], &buffer, &bufsize);
488 grp->gr_mem[i] = NULL;
489
490 *result = grp;
491
492 pthread_mutex_unlock(&grp_lock);
493
494 return 0;
495 #endif
496 }
497
498
499
500
501 void
s_openlog(const char * ident,int logopt,int facility)502 s_openlog(const char *ident, int logopt, int facility)
503 {
504 openlog(ident, logopt
505 #ifdef LOG_DAEMON
506 , facility
507 #endif
508 );
509 }
510
511
512 #ifdef LOG_KERN
513 static struct logfacname
514 {
515 const char *name;
516 int code;
517 } facility[] =
518 {
519 { "kern", LOG_KERN },
520 { "user", LOG_USER },
521 { "mail", LOG_MAIL },
522 { "daemon", LOG_DAEMON },
523 { "auth", LOG_AUTH },
524 { "syslog", LOG_SYSLOG },
525 { "lpr", LOG_LPR },
526 #ifdef LOG_NEWS
527 { "news", LOG_NEWS },
528 #endif
529 #ifdef LOG_UUCP
530 { "uucp", LOG_UUCP },
531 #endif
532 #ifdef LOG_CRON
533 { "cron", LOG_CRON },
534 #endif
535 { "local0", LOG_LOCAL0 },
536 { "local1", LOG_LOCAL1 },
537 { "local2", LOG_LOCAL2 },
538 { "local3", LOG_LOCAL3 },
539 { "local4", LOG_LOCAL4 },
540 { "local5", LOG_LOCAL5 },
541 { "local6", LOG_LOCAL6 },
542 { "local7", LOG_LOCAL7 },
543 { NULL, -1 }
544 };
545
546
547 int
syslog_str2fac(const char * name)548 syslog_str2fac(const char *name)
549 {
550 int i;
551
552 if (name == NULL)
553 return -1;
554
555 if (isdigit(*((unsigned char *)name)))
556 return atoi(name);
557
558 for (i = 0; facility[i].name != NULL &&
559 s_strcasecmp(facility[i].name, name) != 0; i++)
560 ;
561
562 return facility[i].code;
563 }
564
565 #else /* !LOG_KERN */
566
567 int
syslog_str2fac(const char * name)568 syslog_str2fac(const char *name)
569 {
570 return 0;
571 }
572 #endif
573
574
575 #ifdef LOG_EMERG
576 static struct loglevname
577 {
578 const char *name;
579 int level;
580 } level[] =
581 {
582 { "emerg", LOG_EMERG },
583 { "alert", LOG_ALERT },
584 { "crit", LOG_CRIT },
585 { "err", LOG_ERR },
586 { "warning", LOG_WARNING },
587 { "notice", LOG_NOTICE },
588 { "info", LOG_INFO },
589 { "debug", LOG_DEBUG },
590
591 { NULL, -1 }
592 };
593
594
595 int
syslog_str2lev(const char * name)596 syslog_str2lev(const char *name)
597 {
598 int i;
599
600 if (name == NULL)
601 return -1;
602
603 if (isdigit(*((unsigned char *)name)))
604 return atoi(name);
605
606 for (i = 0; level[i].name != NULL &&
607 s_strcasecmp(level[i].name, name) != 0; i++)
608 ;
609
610 return level[i].level;
611 }
612
613 #else /* !LOG_KERN */
614
615 int
syslog_str2fac(const char * name)616 syslog_str2fac(const char *name)
617 {
618 return 0;
619 }
620 #endif
621
622
623
624