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