📄 passwd.c
字号:
#ifndef lintstatic char *sccsid = "@(#)passwd.c 4.5 (ULTRIX) 2/1/91";#endif lint/************************************************************************/************************************************************************ * * * Copyright (c) 1988, 1989, 1990, 1991 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Modification history: * * 07-Aug-90 dlong * Don't reauthenticate before checking minexp and change_pass. Also, * allow root to set any shell. * * 28-Nov-89 dlong * Catch SIGINT and SIGTERM while echo is turned off. Don't terminate if * new password is too long, just warn and truncate. * * 6-Sep-89 dlong * Fixed usage lines for chfn and chsh. Also, only reopen /dev/tty for * passwd command. * * 22-Aug-88 dlong * Check status from GETREQ to prevent infinite looping. * * 18-Aug-89 dlong * Fixed check for user supplied password privilege when using -e. * Also, don't issue message to eat password in -ea mode. * * 16-Aug-89 dws * Added eopt and code to support extended Xprompter protocol. * Cleaned up code in the fopt code path. * * 14-Aug-89 - Synced up hesupd with passwd * * 9-Aug-89 D. Long * Do more checking on pasword form (CHECKCHARS). Use optind for argv[1]. * Include privileged users on password length checks. Don't allow chsh * to work on restricted accounts. Change SEC_TRANS to SEC_UPGRADE. * * 19-Jul-89 - D. Long * Set seed random number generator before making salt. */#include <errno.h>#include <sys/file.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/svcinfo.h>#include <ctype.h>#include <stdio.h>#include <signal.h>#include <sgtty.h>#include <strings.h>#include <pwd.h>#include <grp.h>#include <auth.h>#include <netdb.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/un.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/lock.h>#include <netinet/in.h>#include <sys/param.h>#ifdef AUTHEN#include <krb.h>#endif AUTHEN#define DEFSHELL "/bin/sh"#define CHECKCHARS 3#define ENTRY_SIZE 100#define AUD_BUF_LEN (SYSCALL_MASK_LEN+TRUSTED_MASK_LEN)#define PASSCHG 1#define HESUPD_PORT 800#define HESUPDACK 6#define HESUPDNAK 9#define HESRETRY 3 char bindmaster[] = "bindmaster";char defhome[] = "/var/dss/namedb/src";char *homebase = defhome;struct svcinfo *svcp;int root=0;char *index();struct hesupdmsg { char newcrypt[64]; int opcode; int hesuid; char oldpwd[32]; }; #define NUM_CHOICES 5#define PASSWD_DB "/etc/passwd"#define ETCSHELLS "/etc/shells"extern int min_pw_len, max_pw_len, soft_exp, sec_level;/* Privileged program for changing a users password.*/char *progname = "passwd";static char salt_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";/* Function to read a password from the users terminal with character echoing turned off.*/static int setmodes = 0;static struct sgttyb modes;static int flags, fid;static struct passwd *pwd = (struct passwd *) 0;static struct sockaddr remote_hostaddr;static int remote_hostflag = 0;restoremodes(sig, code, scp)int sig, code, *scp;{ if(setmodes) {/* Restore original tty modes.*/ modes.sg_flags = flags; ioctl(fid, TIOCSETP, &modes); setmodes = 0; } exit(3);}unsigned char *getpass(prompt)char *prompt;{ int last; unsigned char *cp; static unsigned char buff[80]; bzero(buff, sizeof buff);/* Get the current terminal modes.*/ fid = fileno(stdin); ioctl(fid, TIOCGETP, &modes); flags = modes.sg_flags;/* If echo is on, turn it off, prompt for a password, read the password, and restore echo mode.*/ if(flags & ECHO) {/* Turn off echo.*/ setmodes = 1; modes.sg_flags &= ~ECHO; ioctl(fid, TIOCSETP, &modes);/* Prompt for and read the password.*/ fputs(prompt, stdout); cp = (unsigned char *) fgets(buff, sizeof buff, stdin);/* Restore original tty modes.*/ modes.sg_flags = flags; ioctl(fid, TIOCSETP, &modes); setmodes = 0; } else {/* Echo was already off. Prompt for and read the password.*/ fputs(prompt, stdout); cp = (unsigned char *) fgets(buff, sizeof buff, stdin); } if(cp == NULL)/* Error reading input.*/ exit(1);/* Clean up the password.*/ last = strlen(buff) - 1; if(buff[last] == '\n') buff[last] = '\0'; return buff;}/* Function for converting to lower case alphabetics.*/char lcase(c)char c;{ if(c >= 'A' && c <= 'Z') return c|040; else return c;}/* * Function to match a shell name against a pathname. */path_match(path, shell)char *path, *shell;{ char *cp; cp = strchr(path, '\n'); if(cp) *cp = '\0'; if(*shell != '/') { cp = strrchr(path, '/'); if(!cp) cp = path; else cp++; } else cp = path; if(!strcmp(shell, cp)) { return 1; } return 0;}#include "../login.d/proto.h" /* Extended protocol support. */int eopt = 0; /* Global for error macros. *//* * Print an error message. */DO_ERROR(msg)char *msg;{ int i; if (eopt) { REQ rbuf, *req = &rbuf; SENDREQ(req, ERROR, (msg), strlen((msg))); do { GETREQ(req, i); if(i <= 0) exit(2); } while (req->opcode != ACKNOWLEDGE); } else { fputs((msg), stderr); fflush(stderr); }}/* * Print an error message and exit. */#define DO_EXIT(msg, stat) { \ audevent(msg, stat); \ DO_ERROR((msg)); \ exit(stat); \}/* * Generate an audit record. */static void audevent(statustr, status)char *statustr;int status;{ char tmask[AUD_NPARAM]; char *aud_arg[AUD_NPARAM]; int i=0; tmask[i] = T_CHARP; aud_arg[i++] = progname; tmask[i] = T_CHARP; aud_arg[i++] = statustr;/* * Determine if error or result token. */ if(status == 0) tmask[i] = T_RESULT; else tmask[i] = T_ERROR; aud_arg[i++] = (char *) status;/* if(remote_hostflag) { tmask[i] = T_HOSTADDR2; bcopy(remote_hostaddr.sa_data, aud_arg[i++], sizeof (long)); }*/ if(pwd) { tmask[i] = T_CHARP; aud_arg[i++] = pwd->pw_name; tmask[i] = T_UID2; aud_arg[i++] = (char *) pwd->pw_uid; } tmask[i] = '\0';/* * Generate audit record. */ if(audgen(AUTH_EVENT, tmask, aud_arg) == -1 ) perror("audgen" );}/* The main program.*/main(argc, argv)int argc;char *argv[];{ extern char *optarg; extern int optind; AUTHORIZATION *auth, *getauthuid(), *getauthuid_hesiod(); PASSWORD old_pass, new_pass, gen_password[NUM_CHOICES]; PASSWORD verify; CRYPT_PASSWORD crypt_pass; UID user_id, sso_id, our_id, euid; long period, deadline, now, time(); int i, priv=0, owner=0, fopt=0, sopt=0, aopt=0, ypuid=0; char string[MAXPATHLEN+1], salt[3], *cp, *getlogin(), passave[9]; unsigned char *cp2; char hyph_password[MAX_PASSWORD_LENGTH*2], *crypt(), *crypt16(); char user_name[17], *usage; char *getentry(); unsigned char *s; static struct hesupdmsg hupmsg;#ifdef CHECKCHARS int charset=0; static char chartab[256];#endif#ifdef AUTHEN char namebuf[ANAME_SZ]; char *ptr;#endif AUTHEN struct passwd *getpwnam_bind(); struct group *gp; int auth_gid; int hesflg=0; /* set to initially no hesiod stuff */ struct stat stat_buf; char audit_buf[AUD_BUF_LEN];/* turn off auditing of all events except for AUTH events */ if ( audcntl (SET_PROC_ACNTL, (char *)0, 0, AUDIT_AND, 0) == -1) perror ( "audcntl" ); A_PROCMASK_SET ( audit_buf, AUTH_EVENT, 1, 1 ); if (audcntl(SET_PROC_AMASK, audit_buf, AUD_BUF_LEN, 0, 0) == -1 ) perror ( "audcntl" ); progname = strrchr(argv[0], '/'); if(progname) progname++; else progname = argv[0]; signal(SIGINT, restoremodes); signal(SIGTERM, restoremodes); if(!strcmp(progname, "chfn")) { optind = 1; fopt = 1; usage = "usage: chfn [username]\n"; } else if(!strcmp(progname, "chsh")) { optind = 1; sopt = 1; usage = "usage: chsh [username]\n"; } else { usage = "usage: passwd [-aefs] [username]\n"; while((i=getopt(argc, argv, "fsae")) != EOF) switch((char) i) { case 'f': fopt = 1; break; case 's': sopt = 1; break; case 'a': aopt = 1; break; case 'e': eopt = 1; break; case '?': default: DO_EXIT(usage, 1); } } if((eopt || aopt) && (sopt || fopt)) DO_EXIT("passwd: illegal option combination.\n", 1); if(fopt && sopt) DO_EXIT("passwd: Only one of -f and -s allowed.\n", 1);/* Check the command line.*/ if((argc-optind) > 1) DO_EXIT(usage, 1); our_id = getuid(); if(our_id == 0) root=1;/* Process the password configuration file.*/ config_auth();#ifdef AUTHEN if((svcp = getsvc()) == NULL) { DO_EXIT("Cannot access security type\n", 2); } if(svcp->svcauth.seclevel >= SEC_UPGRADE) { for (i = 0 ; svcp->svcpath[SVC_AUTH][i] != SVC_LAST; i++) if (svcp->svcpath[SVC_AUTH][i] == SVC_BIND) { if(gethostname(namebuf, sizeof(namebuf)) == -1) { fputs("gethostname failure\n", stderr); } if((ptr = index(namebuf, '.')) != (char *)0) *ptr = '\0'; if(krb_svc_init("hesiod", namebuf, (char *)NULL, 0, (char *)NULL, "/var/dss/kerberos/tkt/tkt.passwd") != RET_OK) { fputs("Kerberos initialization failure\n", stderr); } } }#endif AUTHEN/* Use the login name as the username if none was suplied on the command line. Get the login name from the current real UID, not utmp.*/ if((argc-optind) > 0) { pwd = getpwnam(argv[optind]); if(!pwd && root) /* allow root to change a hesiod password */ { root=2; pwd = getpwnam_bind(argv[optind]); hesflg=1; } } else pwd = getpwuid(our_id); if(svc_lastlookup == SVC_BIND) { hesflg=1; if(root) root=2; } if(svc_lastlookup == SVC_YP) { ypuid=1; if(sec_level == SEC_UPGRADE) DO_EXIT("YP cannot be used in UPGRADE mode.\n", 2); } if(!pwd) DO_EXIT("User not found in passwd data base.\n", 2); if(!pwd->pw_name) DO_EXIT("Error, no username.\n", 2); strncpy(user_name, pwd->pw_name, sizeof user_name); strncpy(passave, pwd->pw_passwd, sizeof passave);/* The auth file is keyed by UID. Use the usernames UID retrieved from the passwd file as the key.*/ user_id = pwd->pw_uid; if(user_id == our_id) owner = 1; else owner = 0;/* Make sure we are talking to a tty line if not using extended protocol.*/ if (!eopt && !fopt && !sopt) { if(!freopen("/dev/tty", "w", stdout)) DO_EXIT("Unable to write /dev/tty.\n", 2); if(!freopen("/dev/tty", "r", stdin)) DO_EXIT("Unable to read /dev/tty.\n", 2); }/* By definition the SSO is the owner of the auth file. (or the passwd file if we are running BSD compatible).*/ if(sec_level < SEC_UPGRADE) { if(stat(PASSWD_DB, &stat_buf) != 0) DO_EXIT("Cannot stat passwd file.\n", 3); } else if(stat("/etc/auth.dir", &stat_buf) != 0) DO_EXIT("Cannot stat auth file.\n", 3); sso_id = stat_buf.st_uid; euid = geteuid();/* if(euid != sso_id) DO_EXIT("Bad ownership on auth data base or passwd command.\n", 3);*/ if(our_id == sso_id || our_id == 0) priv = 1; else priv = 0;/* Make sure the user is authorized to attempt changing this password.*/ if((!owner && !priv) || (!priv && eopt)) DO_EXIT("Insufficient privilege.\n", 1); umask(022); if(sopt) { char shell[MAXPATHLEN+1], line[MAXPATHLEN+1]; FILE *fp; if(!(fp=fopen(ETCSHELLS, "r"))) { char buf[MAXPATHLEN+50]; strcpy(buf, "Unable to open "); strcat(buf, ETCSHELLS); strcat(buf, "\n"); DO_EXIT(buf, 2); } fputs("Changing login shell for ", stdout); puts(pwd->pw_name); if(!priv && *pwd->pw_shell) { int ok = 0; while(fgets(line, sizeof line, fp)) { if(path_match(line, pwd->pw_shell)) { ok = 1; break; } } if(!ok) { char buf[MAXPATHLEN+50]; strcpy(buf, "Cannot change from restricted shell "); strcat(buf, pwd->pw_shell); strcat(buf, "\n"); DO_EXIT(buf, 1); } rewind(fp); } printf("Shell [%s]: ", pwd->pw_shell); if(!fgets(shell, sizeof shell, stdin)) { DO_EXIT("Login shell unchanged.\n", 0); } cp = strchr(shell, '\n'); if(cp) *cp = '\0'; if(!*shell) { DO_EXIT("Login shell unchanged.\n", 0); } while(fgets(line, sizeof line, fp)) { if(path_match(line, shell)) { strcpy(shell, line); break; } } if(strcmp(shell, line)) { if(priv) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -