rpc.yppasswdd.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 381 行
C
381 行
#ifndef lintstatic char *sccsid = "@(#)rpc.yppasswdd.c 4.1 ULTRIX 7/2/90";#endif lint/**************************************************************** * * * Licensed to Digital Equipment Corporation, Maynard, MA * * Copyright 1985 Sun Microsystems, Inc. * * All rights reserved. * * * ****************************************************************//* Revsions * -------- * * Oct 31, 1989 dal/ Fixed problem handling errors during passwd update * * Apr 20, 1989 jhw/ Fixed security hole * * Jun 12, 1988 jhw/ Fixed username parsing in getpwnam * * Jun 09, 1988 map/ Changed signal handlers to void. * * Jul 30,1986 rjg/ Modified "rename" of temporary passwd file * so that rpc.yppasswdd would work if the source * passwd file existed on another file system. * ie. if /etc/yp is a symbolic link to /usr/etc/yp * the rename would fail. Can't rename across devices. * The Sun makefile at installation time creates a * link /etc/yp to /usr/etc/yp to save space on * the root file system. */#include <sys/param.h>#include <sys/errno.h>#include <stdio.h>#include <signal.h>#include <sys/file.h>#include <rpc/rpc.h>#include <pwd.h>#include <rpcsvc/yppasswd.h>#include <errno.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/wait.h>#include <ctype.h>char *file; /* file in which passwd's are found */char temp[MAXPATHLEN+1];int mflag; /* do a make */char *index();int boilerplate();extern int errno;int Argc;char **Argv;main(argc, argv) char **argv;{ SVCXPRT *transp; int s; Argc = argc; Argv = argv; if (argc < 2) { fprintf(stderr,"usage: %s file [-m arg1 arg2 ...]\n", argv[0]); exit(1); } file = argv[1]; if (access(file, W_OK) < 0) { fprintf(stderr, "can't write %s\n", file); exit(1); } if (argc > 2 && argv[2][0] == '-' && argv[2][1] == 'm') mflag++; if (chdir("/etc/yp") < 0) { fprintf(stderr, "yppasswdd: can't chdir to /etc/yp\n"); exit(1); } if ((s = rresvport()) < 0) { fprintf(stderr, "yppasswdd: can't bind to a privileged socket\n"); exit(1); } transp = svcudp_create(s); if (transp == NULL) { fprintf(stderr, "yppasswdd: couldn't create an RPC server\n"); exit(1); } pmap_unset(YPPASSWDPROG, YPPASSWDVERS); if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, boilerplate, IPPROTO_UDP)) { fprintf(stderr, "yppasswdd: couldn't register yppasswdd\n"); exit(1); } if (fork()) exit(0); { int t; for (t = getdtablesize()-1; t >= 0; t--) if (t != s) (void) close(t); } (void) open("/", O_RDONLY); (void) dup2(0, 1); (void) dup2(0, 2); { int tt = open("/dev/tty", O_RDWR); if (tt > 0) { ioctl(tt, TIOCNOTTY, 0); close(tt); } } svc_run(); fprintf(stderr, "yppasswdd: svc_run shouldn't have returned\n");}boilerplate(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ switch(rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, 0)) fprintf(stderr, "yppasswdd: couldn't reply to RPC call\n"); break; case YPPASSWDPROC_UPDATE: changepasswd(rqstp, transp); break; }}changepasswd(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ int tempfd, lockfd, i, len; static int ans; FILE *tempfp, *filefp; char buf[256], *p, *s; char cmdbuf[BUFSIZ]; void (*f1)(), (*f2)(), (*f3)(); struct passwd *oldpw, *newpw; struct yppasswd yppasswd; union wait status; bzero(&yppasswd, sizeof(yppasswd)); if (!svc_getargs(transp, xdr_yppasswd, &yppasswd)) { svcerr_decode(transp); return; } /* * Clean up from previous changepasswd() call */ while (wait3(&status, WNOHANG, 0) > 0) continue; newpw = &yppasswd.newpw; ans = 1; oldpw = getpwnam(newpw->pw_name); if (oldpw == NULL) { fprintf(stderr, "yppasswdd: no passwd for %s\n", newpw->pw_name); goto done; } if (oldpw->pw_passwd && *oldpw->pw_passwd && strcmp(crypt(yppasswd.oldpass,oldpw->pw_passwd), oldpw->pw_passwd) != 0) { fprintf(stderr, "yppasswdd: %s: bad passwd\n", newpw->pw_name); goto done; } (void) umask(022); f1 = signal(SIGHUP, SIG_IGN); f2 = signal(SIGINT, SIG_IGN); f3 = signal(SIGQUIT, SIG_IGN);/* * Make a temporary file name. */ strcpy(temp, file); if(!strcmp(temp, "/etc/passwd")) strcpy(temp, "/etc/ptmp"); else strcat(temp, ".tmp");/* * Lock the map source file. */ tempfd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644); if (tempfd < 0) { fprintf(stderr, "yppasswdd: "); if (errno == EEXIST) fprintf(stderr, "password file busy - try again.\n"); else perror(temp); goto cleanup_noclose; } signal(SIGTSTP, SIG_IGN); if ((tempfp = fdopen(tempfd, "w")) == NULL) { fprintf(stderr, "yppasswdd: fdopen failed?\n"); goto cleanup; } /* * Copy passwd to temp, replacing matching lines * with new password. */ if ((filefp = fopen(file, "r")) == NULL) { fprintf(stderr, "yppasswdd: fopen of %s failed?\n", file); fclose(tempfp); goto cleanup; } len = strlen(newpw->pw_name); /* * This fixes a really bogus security hole, basically anyone can * call the rpc passwd deamon, give them their own passwd and a * new one that consists of ':0:0:Im root now:/:/bin/csh^J' and * give themselves root access. With this code it will simply make * it impossible for them to login again, and as a bonus leave * a cookie for the always vigilant system administrator to ferret * them out. */ for (p = newpw->pw_passwd; (*p != '\0'); p++) if ((*p == ':') || !(isprint(*p))) *p = '$'; /* you lose buckwheat */ while (fgets(buf, sizeof(buf), filefp)) { p = index(buf, ':'); if (p && p - buf == len && strncmp(newpw->pw_name, buf, p - buf) == 0) { fprintf(tempfp,"%s:%s:%d:%d:%s:%s:%s\n", oldpw->pw_name, newpw->pw_passwd, oldpw->pw_uid, oldpw->pw_gid, oldpw->pw_gecos, oldpw->pw_dir, oldpw->pw_shell); } else fputs(buf, tempfp); } fclose(filefp); fflush(tempfp); if(ferror(tempfp)) { fputs("yppasswdd: ", stderr); perror("fflush()"); fclose(tempfp); goto cleanup; } fclose(tempfp); /* Original version of Sun code that fails when /etc/yp * is a symbolic link to /usr/etc/yp */ if (rename(temp, file) < 0) { fprintf(stderr, "yppasswdd: "); perror("rename"); unlink(temp); goto cleanup_noclose; } /* make sure that original file is secure */ chmod(file, 0644); ans = 0; if (mflag && fork() == 0) { strcpy(cmdbuf, "make"); for (i = 3; i < Argc; i++) { strcat(cmdbuf, " "); strcat(cmdbuf, Argv[i]); } (void) umask(022); system(cmdbuf); exit(0); } cleanup: unlink(temp); close(tempfd); cleanup_noclose: signal(SIGHUP, f1); signal(SIGINT, f2); signal(SIGQUIT, f3); done: if (!svc_sendreply(transp, xdr_int, &ans)) fprintf(stderr, "yppasswdd: couldnt reply to RPC call\n");}rresvport(){ struct sockaddr_in sin; int s, alport = IPPORT_RESERVED - 1; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0;#if 0 s = socket(AF_INET, SOCK_DGRAM, 0, 0);#endif s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) return (-1); for (;;) { sin.sin_port = htons((u_short)alport); if (bind(s, (caddr_t)&sin, sizeof (sin), 0) >= 0) return (s); if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { perror("socket"); return (-1); } (alport)--; if (alport == IPPORT_RESERVED/2) { fprintf(stderr, "socket: All ports in use\n"); return (-1); } }}static char *pwskip(p)register char *p;{ while( *p && *p != ':' && *p != '\n' ) ++p; if( *p ) *p++ = 0; return(p);}pwcmp(s1,s2)register char *s1, *s2;{ while (*s1 == *s2) /* bump while they match */ { *s1++; *s2++; } if(*s1 == '\0' && *s2 == ':') /* format specific solution */ return(0); return(1);} struct passwd *getpwnam(name) char *name;{ FILE *pwf; int cnt; char *p; static char line[BUFSIZ+1]; static struct passwd passwd; pwf = fopen(file, "r"); if (pwf == NULL) return (NULL); cnt = strlen(name); while ((p = fgets(line, BUFSIZ, pwf)) && pwcmp(name, line)) continue; if (p) { passwd.pw_name = p; p = pwskip(p); passwd.pw_passwd = p; p = pwskip(p); passwd.pw_uid = atoi(p); p = pwskip(p); passwd.pw_gid = atoi(p); passwd.pw_quota = 0; passwd.pw_comment = ""; p = pwskip(p); passwd.pw_gecos = p; p = pwskip(p); passwd.pw_dir = p; p = pwskip(p); passwd.pw_shell = p; while(*p && *p != '\n') p++; *p = '\0'; fclose(pwf); return (&passwd); } else { fclose(pwf); return (NULL); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?