1/* pwcheck.c -- Unix pwcheck daemon 2 $Id: pwcheck.c,v 1.2 2004/07/07 22:53:07 snsimon Exp $ 3Copyright 1998, 1999 Carnegie Mellon University 4 5 All Rights Reserved 6 7Permission to use, copy, modify, and distribute this software and its 8documentation for any purpose and without fee is hereby granted, 9provided that the above copyright notice appear in all copies and that 10both that copyright notice and this permission notice appear in 11supporting documentation, and that the name of Carnegie Mellon 12University not be used in advertising or publicity pertaining to 13distribution of the software without specific, written prior 14permission. 15 16CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 17THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 18FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR 19ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 22OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23******************************************************************/ 24 25#include <config.h> 26 27#ifdef HAVE_UNISTD_H 28#include <unistd.h> 29#endif 30#include <stdio.h> 31#include <errno.h> 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/socket.h> 35#include <sys/un.h> 36#include <sys/stat.h> 37#include <fcntl.h> 38#ifdef HAVE_PATHS_H 39#include <paths.h> 40#endif 41#include <syslog.h> 42 43#if !defined(_PATH_PWCHECKPID) 44#ifdef _PATH_VARRUN 45# define _PATH_PWCHECKPID (_PATH_VARRUN "pwcheck.pid") 46#else 47# define _PATH_PWCHECKPID (NULL) 48#endif 49#endif 50 51void newclient(int); 52int retry_write(int, const char *, unsigned int); 53 54/* 55 * Unix pwcheck daemon-authenticated login (shadow password) 56 */ 57 58int 59main() 60{ 61 char fnamebuf[MAXPATHLEN]; 62 int s; 63 int c; 64 int count; 65 int rc; 66 struct sockaddr_un srvaddr; 67 struct sockaddr_un clientaddr; 68 int r; 69 int len; 70 mode_t oldumask; 71 char *pid_file = _PATH_PWCHECKPID; 72 FILE *fp = NULL; 73 pid_t pid; 74 75 openlog("pwcheck", LOG_NDELAY, LOG_AUTH); 76 77 /* Daemonize. */ 78 count = 5; 79 while (count--) { 80 pid = fork(); 81 82 if (pid > 0) 83 _exit(0); /* parent dies */ 84 85 if ((pid == -1) && (errno == EAGAIN)) { 86 syslog(LOG_WARNING, "master fork failed (sleeping): %m"); 87 sleep(5); 88 continue; 89 } 90 } 91 if (pid == -1) { 92 rc = errno; 93 syslog(LOG_ERR, "FATAL: master fork failed: %m"); 94 fprintf(stderr, "pwcheck: "); 95 errno = rc; 96 perror("fork"); 97 exit(1); 98 } 99 100 /* 101 * We're now running in the child. Lose our controlling terminal 102 * and obtain a new process group. 103 */ 104 if (setsid() == -1) { 105 rc = errno; 106 syslog(LOG_ERR, "FATAL: setsid: %m"); 107 fprintf(stderr, "pwcheck: "); 108 errno = rc; 109 perror("setsid"); 110 exit(1); 111 } 112 113 s = open("/dev/null", O_RDWR, 0); 114 if (s == -1) { 115 rc = errno; 116 syslog(LOG_ERR, "FATAL: /dev/null: %m"); 117 fprintf(stderr, "pwcheck: "); 118 errno = rc; 119 perror("/dev/null"); 120 exit(1); 121 122 } 123 dup2(s, fileno(stdin)); 124 dup2(s, fileno(stdout)); 125 dup2(s, fileno(stderr)); 126 if (s > 2) { 127 close(s); 128 } 129 130 /* 131 * Record process ID - shamelessly stolen from inetd (I.V.) 132 */ 133 pid = getpid(); 134 if (pid_file) { 135 fp = fopen(pid_file, "w"); 136 } 137 if (fp) { 138 fprintf(fp, "%ld\n", (long)pid); 139 fclose(fp); 140 } else if (pid_file) { 141 syslog(LOG_WARNING, "%s: %m", pid_file); 142 } 143 144 s = socket(AF_UNIX, SOCK_STREAM, 0); 145 if (s == -1) { 146 perror("socket"); 147 exit(1); 148 } 149 150 strncpy(fnamebuf, PWCHECKDIR, sizeof(fnamebuf)); 151 strncpy(fnamebuf + sizeof(PWCHECKDIR)-1, "/pwcheck", 152 sizeof(fnamebuf) - sizeof(PWCHECKDIR)); 153 fnamebuf[MAXPATHLEN-1] = '\0'; 154 155 (void) unlink(fnamebuf); 156 157 memset((char *)&srvaddr, 0, sizeof(srvaddr)); 158 srvaddr.sun_family = AF_UNIX; 159 strncpy(srvaddr.sun_path, fnamebuf, sizeof(srvaddr.sun_path)); 160 /* Most systems make sockets 0777 no matter what you ask for. 161 Known exceptions are Linux and DUX. */ 162 oldumask = umask((mode_t) 0); /* for Linux, which observes the umask when 163 setting up the socket */ 164 r = bind(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); 165 if (r == -1) { 166 syslog(LOG_ERR, "%.*s: %m", 167 sizeof(srvaddr.sun_path), srvaddr.sun_path); 168 exit(1); 169 } 170 umask(oldumask); /* for Linux */ 171 chmod(fnamebuf, (mode_t) 0777); /* for DUX, where this isn't the default. 172 (harmlessly fails on some systems) */ 173 r = listen(s, 5); 174 if (r == -1) { 175 syslog(LOG_ERR, "listen: %m"); 176 exit(1); 177 } 178 179 for (;;) { 180 len = sizeof(clientaddr); 181 c = accept(s, (struct sockaddr *)&clientaddr, &len); 182 if (c == -1 && errno != EINTR) { 183 syslog(LOG_WARNING, "accept: %m"); 184 continue; 185 } 186 187 newclient(c); 188 } 189} 190 191void newclient(int c) 192{ 193 char request[1024]; 194 int n; 195 unsigned int start; 196 char *reply; 197 extern char *pwcheck(); 198 199 start = 0; 200 while (start < sizeof(request) - 1) { 201 n = read(c, request+start, sizeof(request) - 1 - start); 202 if (n < 1) { 203 reply = "Error reading request"; 204 goto sendreply; 205 } 206 207 start += n; 208 209 if (request[start-1] == '\0' && strlen(request) < start) { 210 break; 211 } 212 } 213 214 if (start >= sizeof(request) - 1) { 215 reply = "Request too big"; 216 } 217 else { 218 reply = pwcheck(request, request + strlen(request) + 1); 219 } 220 221sendreply: 222 223 retry_write(c, reply, strlen(reply)); 224 close(c); 225} 226 227/* 228 * Keep calling the write() system call with 'fd', 'buf', and 'nbyte' 229 * until all the data is written out or an error occurs. 230 */ 231int retry_write(int fd, const char *buf, unsigned int nbyte) 232{ 233 int n; 234 int written = 0; 235 236 if (nbyte == 0) 237 return 0; 238 239 for (;;) { 240 n = write(fd, buf, nbyte); 241 if (n == -1) { 242 if (errno == EINTR) 243 continue; 244 return -1; 245 } 246 247 written += n; 248 249 if ((unsigned int) n >= nbyte) 250 return written; 251 252 buf += n; 253 nbyte -= n; 254 } 255} 256