static VALUE rb_shadow_putspent(VALUE self, VALUE entry, VALUE file) { struct spwd centry; FILE* cfile; VALUE val[9]; int i; int result; for(i=0; i<=8; i++) val[i] = RSTRUCT_PTR(entry)[i]; cfile = file_ptr(RFILE(file)->fptr); centry.sp_namp = StringValuePtr(val[0]); centry.sp_pwdp = StringValuePtr(val[1]); centry.sp_lstchg = FIX2INT(val[2]); centry.sp_min = FIX2INT(val[3]); centry.sp_max = FIX2INT(val[4]); centry.sp_warn = FIX2INT(val[5]); centry.sp_inact = FIX2INT(val[6]); centry.sp_expire = FIX2INT(val[7]); centry.sp_flag = FIX2INT(val[8]); result = putspent(¢ry,cfile); if( result == -1 ) rb_raise(rb_eStandardError,"can't change password"); return Qtrue; };
// {{{ user_set_password() /// Set the password for the specified username void user_set_password(user_t *o, char *username, volatile char* passwd) { FILE *f; struct spwd *sp = NULL; o->error[0]=0; sp = getspnam(username); if(!sp) { sstrncpy(o->error, "user_set_password() unknown user", USER_ERROR_SIZE); return; } /* salt */ struct timeval tv; static char salt[40]; salt[0] = '\0'; gettimeofday (&tv, (struct timezone *) 0); strcat(salt, l64a (tv.tv_usec)); strcat(salt, l64a (tv.tv_sec + getpid () + clock ())); if (strlen (salt) > 3 + 8) salt[11] = '\0'; /* shadow */ sp->sp_pwdp = (char*)crypt((const char*)passwd, salt); if(user_del_line(username, "/etc/shadow")!=0) { sstrncpy(o->error, "user_set_password() cannot modify /etc/shadow", USER_ERROR_SIZE); return; } f = fopen("/etc/shadow", "a+"); if(!f) { sstrncpy(o->error, "user_set_password(): cannot open /etc/shadow", USER_ERROR_SIZE); return; } if (putspent(sp, f) == -1) { sstrncpy(o->error, "user_add(): putspent() error", USER_ERROR_SIZE); return; } fclose(f); }
static int _update_shadow(const char *forwho, char *towhat) { struct spwd *spwdent = NULL, *stmpent = NULL; FILE *pwfile, *opwfile; int err = 1; int oldmask; spwdent = getspnam(forwho); if (spwdent == NULL) { return PAM_USER_UNKNOWN; } oldmask = umask(077); pwfile = fopen(SH_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { return PAM_AUTHTOK_ERR; } opwfile = fopen("/etc/shadow", "r"); if (opwfile == NULL) { fclose(pwfile); return PAM_AUTHTOK_ERR; } chown(SH_TMPFILE, 0, 0); chmod(SH_TMPFILE, 0600); stmpent = fgetspent(opwfile); while (stmpent) { if (!strcmp(stmpent->sp_namp, forwho)) { stmpent->sp_pwdp = towhat; stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); err = 0; D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); } if (putspent(stmpent, pwfile)) { D(("error writing entry to shadow file: %s\n", strerror(errno))); err = 1; break; } stmpent = fgetspent(opwfile); } fclose(opwfile); if (fclose(pwfile)) { D(("error writing entries to shadow file: %s\n", strerror(errno))); err = 1; } if (!err) { rename(SH_TMPFILE, "/etc/shadow"); return PAM_SUCCESS; } else { unlink(SH_TMPFILE); return PAM_AUTHTOK_ERR; } }
static int shadow_put (const void *ent, FILE * file) { const struct spwd *sp = ent; if ( (NULL == sp) || (valid_field (sp->sp_namp, ":\n") == -1) || (valid_field (sp->sp_pwdp, ":\n") == -1)) { return -1; } return (putspent (sp, file) == -1) ? -1 : 0; }
static int write_root_shadow(const char *path, const struct spwd *p) { _cleanup_fclose_ FILE *f = NULL; assert(path); assert(p); RUN_WITH_UMASK(0777) f = fopen(path, "wex"); if (!f) return -errno; errno = 0; if (putspent(p, f) != 0) return errno ? -errno : -EIO; return fflush_and_check(f); }
static int shadow_put(const void *ent, FILE *file) { const struct spwd *sp = ent; return (putspent(sp, file) == -1) ? -1 : 0; }
/* * files_update_shadow(char *name, struct spwd *spwd) * * update the shadow password file SHADOW to contain the spwd structure * "spwd" for user "name" */ int files_update_shadow(char *name, struct spwd *spwd) { struct stat64 stbuf; FILE *dst; FILE *src; struct spwd cur; char buf[SPW_SCRATCH_SIZE]; int tempfd; mode_t filemode; int result = -1; int err = PWU_SUCCESS; /* Mode of the shadow file should be 400 or 000 */ if (stat64(SHADOW, &stbuf) < 0) { err = PWU_STAT_FAILED; goto shadow_exit; } /* copy mode from current shadow file (0400 or 0000) */ filemode = stbuf.st_mode & S_IRUSR; /* * we can't specify filemodes to fopen(), and we SHOULD NOT * set umask in multi-thread safe libraries, so we use * a combination of open() and fdopen() */ tempfd = open(SHADTEMP, O_WRONLY|O_CREAT|O_TRUNC, filemode); if (tempfd < 0) { err = PWU_OPEN_FAILED; goto shadow_exit; } (void) fchown(tempfd, (uid_t)0, stbuf.st_gid); if ((dst = fdopen(tempfd, "wF")) == NULL) { err = PWU_OPEN_FAILED; goto shadow_exit; } if ((src = fopen(SHADOW, "rF")) == NULL) { err = PWU_OPEN_FAILED; (void) fclose(dst); (void) unlink(SHADTEMP); goto shadow_exit; } /* * copy old shadow to temporary file while replacing the entry * that matches "name". */ while (fgetspent_r(src, &cur, buf, sizeof (buf)) != NULL) { if (strcmp(cur.sp_namp, name) == 0) result = putspent(spwd, dst); else result = putspent(&cur, dst); if (result != 0) { err = PWU_WRITE_FAILED; (void) fclose(src); (void) fclose(dst); goto shadow_exit; } } (void) fclose(src); if (fclose(dst) != 0) { /* * Something went wrong (ENOSPC for example). Don't * use the resulting temporary file! */ err = PWU_CLOSE_FAILED; (void) unlink(SHADTEMP); goto shadow_exit; } /* * Rename stmp to shadow: * 1. make sure /etc/oshadow is gone * 2. ln /etc/shadow /etc/oshadow * 3. mv /etc/stmp /etc/shadow */ if (unlink(OSHADOW) && access(OSHADOW, 0) == 0) { err = PWU_UPDATE_FAILED; (void) unlink(SHADTEMP); goto shadow_exit; } if (link(SHADOW, OSHADOW) == -1) { err = PWU_UPDATE_FAILED; (void) unlink(SHADTEMP); goto shadow_exit; } if (rename(SHADTEMP, SHADOW) == -1) { err = PWU_UPDATE_FAILED; (void) unlink(SHADTEMP); goto shadow_exit; } (void) unlink(OSHADOW); shadow_exit: return (err); }
int auth_change_pwd(char *user, char *newpwd) { struct passwd *spw; struct spwd *stp; char hash[35] = ""; long today; FILE *fd; if (0 != lckpwdf()) { return 1; } /* open passwd */ spw = getpwnam(user); if (spw == 0) { return 1; } if (g_strncmp(spw->pw_passwd, "x", 3) != 0) { /* old system with only passwd */ if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0) { ulckpwdf(); return 1; } spw->pw_passwd = g_strdup(hash); fd = fopen("/etc/passwd", "rw"); putpwent(spw, fd); } else { /* the system is using shadow */ stp = getspnam(user); if (stp == 0) { return 1; } /* old system with only passwd */ if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0) { ulckpwdf(); return 1; } stp->sp_pwdp = g_strdup(hash); today = g_time1() / SECS_PER_DAY; stp->sp_lstchg = today; stp->sp_expire = today + stp->sp_max + stp->sp_inact; fd = fopen("/etc/shadow", "rw"); putspent(stp, fd); } ulckpwdf(); return 0; }
PAMH_ARG_DECL(int unix_update_shadow, const char *forwho, char *towhat) { struct spwd spwdent, *stmpent = NULL; struct stat st; FILE *pwfile, *opwfile; int err = 0; int oldmask; int wroteentry = 0; #ifdef WITH_SELINUX security_context_t prev_context=NULL; #endif oldmask = umask(077); #ifdef WITH_SELINUX if (SELINUX_ENABLED) { security_context_t shadow_context=NULL; if (getfilecon("/etc/shadow",&shadow_context)<0) { return PAM_AUTHTOK_ERR; }; if (getfscreatecon(&prev_context)<0) { freecon(shadow_context); return PAM_AUTHTOK_ERR; } if (setfscreatecon(shadow_context)) { freecon(shadow_context); freecon(prev_context); return PAM_AUTHTOK_ERR; } freecon(shadow_context); } #endif pwfile = fopen(SH_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { err = 1; goto done; } opwfile = fopen("/etc/shadow", "r"); if (opwfile == NULL) { fclose(pwfile); err = 1; goto done; } if (fstat(fileno(opwfile), &st) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } if (fchmod(fileno(pwfile), st.st_mode) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } stmpent = fgetspent(opwfile); while (stmpent) { if (!strcmp(stmpent->sp_namp, forwho)) { stmpent->sp_pwdp = towhat; stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24); if (stmpent->sp_lstchg == 0) stmpent->sp_lstchg = -1; /* Don't request passwort change only because time isn't set yet. */ wroteentry = 1; D(("Set password %s for %s", stmpent->sp_pwdp, forwho)); } if (putspent(stmpent, pwfile)) { D(("error writing entry to shadow file: %m")); err = 1; break; } stmpent = fgetspent(opwfile); } fclose(opwfile); if (!wroteentry && !err) { spwdent.sp_namp = forwho; spwdent.sp_pwdp = towhat; spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24); if (spwdent.sp_lstchg == 0) spwdent.sp_lstchg = -1; /* Don't request passwort change only because time isn't set yet. */ spwdent.sp_min = spwdent.sp_max = spwdent.sp_warn = spwdent.sp_inact = spwdent.sp_expire = -1; spwdent.sp_flag = (unsigned long)-1l; if (putspent(&spwdent, pwfile)) { D(("error writing entry to shadow file: %m")); err = 1; } } if (fflush(pwfile) || fsync(fileno(pwfile))) { D(("fflush or fsync error writing entries to shadow file: %m")); err = 1; } if (fclose(pwfile)) { D(("fclose error writing entries to shadow file: %m")); err = 1; } done: if (!err) { if (!rename(SH_TMPFILE, "/etc/shadow")) pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho); else err = 1; } #ifdef WITH_SELINUX if (SELINUX_ENABLED) { if (setfscreatecon(prev_context)) { err = 1; } if (prev_context) freecon(prev_context); prev_context=NULL; } #endif if (!err) { return PAM_SUCCESS; } else { unlink(SH_TMPFILE); return PAM_AUTHTOK_ERR; } }
static const char* set_passwd(const char *name, const char *passwd, char **msg) { FILE *f = NULL; struct spwd *spwd, new_spwd; const char *en_passwd; /* encrypted password */ struct stat st; assert(name); assert(passwd); /* check password format */ if ((passwd[0] != '$') || (passwd[1] != '0' && passwd[1] != '1' && passwd[1] != '5' && passwd[1] != '6') || (passwd[2] != '$')) { asprintf(msg, "Wrong password format (user %s).", name); return (NULL); } if (passwd[1] == '0') { /* encrypt the password */ get_login_defs(); en_passwd = pw_encrypt(&(passwd[3]), crypt_make_salt(NULL, NULL)); } else { en_passwd = passwd; } /* * store encrypted password into shadow */ /* lock shadow file */ if (lckpwdf() != 0) { *msg = strdup("Failed to acquire shadow file lock."); return (NULL); } /* init position in shadow */ setspent(); /* open new shadow */ f = fopen(SHADOW_COPY, "w"); if (f == NULL) { asprintf(msg, "Unable to prepare shadow copy (%s).", strerror(errno)); endspent(); ulckpwdf(); return (NULL); } /* get file stat of the original file to make a nice copy of it */ stat(SHADOW_ORIG, &st); fchmod(fileno(f), st.st_mode); fchown(fileno(f), st.st_uid, st.st_gid); while ((spwd = getspent()) != NULL) { if (strcmp(spwd->sp_namp, name) == 0) { /* * we have the entry to change, * make the copy, modifying the original * structure doesn't seem as a good idea */ memcpy(&new_spwd, spwd, sizeof(struct spwd)); new_spwd.sp_pwdp = (char*) en_passwd; spwd = &new_spwd; } /* store the record into the shadow copy */ putspent(spwd, f); } endspent(); fclose(f); if (rename(SHADOW_COPY, SHADOW_ORIG) == -1) { asprintf(msg, "Unable to rewrite shadow database (%s).", strerror(errno)); unlink(SHADOW_COPY); ulckpwdf(); return (NULL); } ulckpwdf(); return (en_passwd); }
void changepasswd(SVCXPRT *transp) { /* * Put these numeric constants into const variables so * a) they're visible in a debugger * b) the compiler can play it's cool games with em */ static const int cryptpwsize = CRYPT_MAXCIPHERTEXTLEN; static const int fingersize = FINGERSIZE; static const int shellsize = SHELLSIZE; struct yppasswd yppwd; struct passwd newpw, opwd; struct spwd ospwd; struct sigaction sa, osa1, osa2, osa3; struct stat pwstat, spstat, adjstat; char *oldpass_crypt = NULL; char newpasswdfile[FILENAME_MAX]; char newshadowfile[FILENAME_MAX]; char newadjunctfile[FILENAME_MAX]; char tmppasswdfile[FILENAME_MAX]; char tmpshadowfile[FILENAME_MAX]; char tmpadjunctfile[FILENAME_MAX]; char pwbuf[NSS_LINELEN_PASSWD], spbuf[NSS_LINELEN_SHADOW]; char adjbuf[BUFSIZ+1], adjbuf_new[BUFSIZ+1], cmdbuf[BUFSIZ]; char adj_encrypt[CRYPT_MAXCIPHERTEXTLEN + 1]; /* * The adj_crypt_* pointers are used to point into adjbuf * NOT adj_encrypt */ char *adj_crypt_begin, *adj_crypt_end; char name[UTUSERLEN + sizeof (":")]; char *p; FILE *opwfp = NULL, *ospfp = NULL, *oadjfp = NULL, *npwfp = NULL, *nspfp = NULL, *nadjfp = NULL; int npwfd = -1, nspfd = -1, nadjfd = -1; int i, ans, chsh, chpw, chgecos, namelen; int gotadjunct = 0, gotshadow = 0, gotpasswd = 0; int doneflag = 0, root_on_master = 0; pid_t retval; time_t now; long pwpos = 0, sppos = 0; /* Globals :-( */ extern int single, nogecos, noshell, nopw, mflag, Mstart, Argc; extern char **Argv; extern char passwd_file[], shadow_file[], adjunct_file[]; extern int useadjunct; extern int useshadow; /* Clean out yppwd */ memset(&yppwd, 0, sizeof (struct yppasswd)); /* Get the RPC args */ if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) { svcerr_decode(transp); return; } /* Perform basic validation */ if (/* (!validstr(yppwd.oldpass, PWSIZE)) || */ /* see PR:nis/38 */ (!validstr(yppwd.newpw.pw_passwd, cryptpwsize)) || (!validstr(yppwd.newpw.pw_name, UTUSERLEN)) || (!validstr(yppwd.newpw.pw_gecos, fingersize)) || (!validstr(yppwd.newpw.pw_shell, shellsize))) { svcerr_decode(transp); return; } /* * Special case: root on the master server can change other users' * passwords without first entering the old password. We need to * ensure that this is indeed root on the master server. (bug 1253949) */ if (strcmp(transp->xp_netid, "ticlts") == 0) { svc_local_cred_t cred; if (!svc_get_local_cred(transp, &cred)) { syslog(LOG_ERR, "yppasswdd: Couldn't get " "local user credentials.\n"); } else if (cred.ruid == 0) root_on_master = 1; } newpw = yppwd.newpw; strcpy(name, newpw.pw_name); strcat(name, ":"); namelen = strlen(name); ans = 2; chsh = chpw = chgecos = 0; /* Get all the filenames straight */ strcpy(newpasswdfile, passwd_file); strcat(newpasswdfile, ".ptmp"); strcpy(newshadowfile, shadow_file); strcat(newshadowfile, ".ptmp"); strcpy(newadjunctfile, adjunct_file); strcat(newadjunctfile, ".ptmp"); memset(&sa, 0, sizeof (struct sigaction)); sa.sa_handler = SIG_IGN; sigaction(SIGTSTP, &sa, (struct sigaction *)0); sigaction(SIGHUP, &sa, &osa1); sigaction(SIGINT, &sa, &osa2); sigaction(SIGQUIT, &sa, &osa3); /* Lock, then open the passwd and shadow files */ if (yplckpwdf() < 0) { syslog(LOG_ERR, "yppasswdd: Password file(s) busy. " "Try again later.\n"); ans = 8; goto cleanup; } if ((opwfp = fopen(passwd_file, "r")) == NULL) { syslog(LOG_ERR, "yppasswdd: Could not open %s\n", passwd_file); goto cleanup; } fstat(fileno(opwfp), &pwstat); if (useshadow) { if ((ospfp = fopen(shadow_file, "r")) == NULL) { syslog(LOG_ERR, "yppasswdd: Could not open %s\n", shadow_file); goto cleanup; } fstat(fileno(ospfp), &spstat); } if (useadjunct) { if ((oadjfp = fopen(adjunct_file, "r")) == NULL) { syslog(LOG_ERR, "yppasswdd: Could not open %s\n", adjunct_file); goto cleanup; } fstat(fileno(oadjfp), &adjstat); } /* * Open the new passwd and shadow tmp files, * first with open and then create a FILE * with fdopen() */ if ((npwfd = open(newpasswdfile, O_WRONLY | O_CREAT | O_EXCL, pwstat.st_mode)) < 0) { if (errno == EEXIST) { syslog(LOG_WARNING, "yppasswdd: passwd file busy - try again\n"); ans = 8; } else { syslog(LOG_ERR, "yppasswdd: %s: %m", newpasswdfile); ans = 9; } goto cleanup; } fchown(npwfd, pwstat.st_uid, pwstat.st_gid); if ((npwfp = fdopen(npwfd, "w")) == NULL) { syslog(LOG_ERR, "yppasswdd: fdopen() on %s failed\n", newpasswdfile); goto cleanup; } if (useshadow) { if ((nspfd = open(newshadowfile, O_WRONLY | O_CREAT | O_EXCL, spstat.st_mode)) < 0) { if (errno == EEXIST) { syslog(LOG_WARNING, "yppasswdd: shadow file busy - try " "again\n"); ans = 8; } else { syslog(LOG_ERR, "yppasswdd: %s: %m", newshadowfile); ans = 9; } goto cleanup; } fchown(nspfd, spstat.st_uid, spstat.st_gid); if ((nspfp = fdopen(nspfd, "w")) == NULL) { syslog(LOG_ERR, "yppasswdd: fdopen() on %s failed\n", newshadowfile); goto cleanup; } } if (useadjunct) { if ((nadjfd = open(newadjunctfile, O_WRONLY | O_CREAT | O_EXCL, adjstat.st_mode)) < 0) { if (errno == EEXIST) { syslog(LOG_WARNING, "yppasswdd: adjunct file busy - try " "again\n"); ans = 8; } else { syslog(LOG_ERR, "yppasswdd: %s: %m", newadjunctfile); ans = 9; } goto cleanup; } fchown(nadjfd, adjstat.st_uid, adjstat.st_gid); if ((nadjfp = fdopen(nadjfd, "w")) == NULL) { syslog(LOG_ERR, "yppasswdd: fdopen() on %s failed\n", newadjunctfile); goto cleanup; } } /* * The following code may not seem all that elegant, but my * interpretation of the man pages relating to the passwd and * shadow files would seem to indicate that there is no guarantee * that the entries contained in those files will be in the same * order... * * So here's the high level overview: * * Loop through the passwd file reading in lines and writing them * out to the new file UNTIL we get to the correct entry. * IF we have a shadow file, loop through it reading in lines and * writing them out to the new file UNTIL we get to the correct * entry. IF we have an adjunct file, loop through it reading in * lines and writing them out to the new file UNTIL we get to the * correct entry. * * Figure out what's changing, contruct the new passwd, shadow, * and adjunct entries and spit em out to the temp files. * At this point, set the done flag and leap back into the loop(s) * until you're finished with the files and then leap to the * section that installs the new files. */ loop_in_files: /* While we find things in the passwd file */ while (fgets(pwbuf, NSS_LINELEN_PASSWD, opwfp)) { /* * Is this the passwd entry we want? * If not, then write it out to the new passwd temp file * and remember our position. */ if (doneflag || strncmp(name, pwbuf, namelen)) { if (fputs(pwbuf, npwfp) == EOF) { syslog(LOG_ERR, "yppasswdd: write to passwd file " "failed.\n"); goto cleanup; } pwpos = ftell(opwfp); continue; } gotpasswd = 1; break; } /* no match */ if (!gotpasswd) { syslog(LOG_ERR, "yppasswdd: user %s does not exist\n", name); goto cleanup; } /* While we find things in the shadow file */ while (useshadow && fgets(spbuf, NSS_LINELEN_SHADOW, ospfp)) { /* * Is this the shadow entry that we want? * If not, write it out to the new shadow temp file * and remember our position. */ if (doneflag || strncmp(name, spbuf, namelen)) { if (fputs(spbuf, nspfp) == EOF) { syslog(LOG_ERR, "yppasswdd: write to shadow file " "failed.\n"); goto cleanup; } sppos = ftell(ospfp); continue; } gotshadow = 1; break; } /* While we find things in the adjunct file */ while (useadjunct && fgets(adjbuf, BUFSIZ, oadjfp)) { /* * is this the adjunct entry that we want? * If not, write it out to the new temp file * and remember our position. */ if (doneflag || strncmp(name, adjbuf, namelen)) { if (fputs(adjbuf, nadjfp) == EOF) { syslog(LOG_ERR, "yppasswdd: write to adjunct file " "failed.\n"); goto cleanup; } continue; } gotadjunct = 1; break; } if (doneflag) goto install_files; if (useshadow && !gotshadow) { syslog(LOG_ERR, "yppasswdd: no passwd in shadow for %s\n", newpw.pw_name); ans = 4; goto cleanup; } if (useadjunct && !gotadjunct) { syslog(LOG_ERR, "yppasswdd: no passwd in adjunct for %s\n", newpw.pw_name); ans = 4; goto cleanup; } /* * Now that we've read in the correct passwd AND * shadow lines, we'll rewind to the beginning of * those lines and let the fget*ent() calls do * the work. Since we are only working with the * first two fields of the adjunct entry, leave * it as a char array. */ fseek(opwfp, pwpos, SEEK_SET); opwd = *fgetpwent(opwfp); if (useshadow) { fseek(ospfp, sppos, SEEK_SET); ospwd = *fgetspent(ospfp); } oldpass_crypt = cryptoldpasswd(yppwd.oldpass, newpw.pw_passwd, newpw.pw_name); if (oldpass_crypt == NULL) { ans = 3; goto cleanup; } p = newpw.pw_passwd; if ((!nopw) && p && *p && !((*p++ == '#') && (*p++ == '#') && (strcmp(p, opwd.pw_name) == 0)) && (strcmp(oldpass_crypt, newpw.pw_passwd) != 0)) chpw = 1; oldpass_crypt = NULL; if ((!noshell) && (strcmp(opwd.pw_shell, newpw.pw_shell) != 0)) { if (single) chpw = 0; chsh = 1; } if ((!nogecos) && (strcmp(opwd.pw_gecos, newpw.pw_gecos) != 0)) { if (single) { chpw = 0; chsh = 0; } chgecos = 1; } if (!(chpw + chsh + chgecos)) { syslog(LOG_NOTICE, "yppasswdd: no change for %s\n", newpw.pw_name); ans = 3; goto cleanup; } if (useshadow && !root_on_master) { oldpass_crypt = cryptoldpasswd(yppwd.oldpass, ospwd.sp_pwdp, newpw.pw_name); if (oldpass_crypt == NULL) goto cleanup; if (ospwd.sp_pwdp && *ospwd.sp_pwdp && (strcmp(oldpass_crypt, ospwd.sp_pwdp) != 0)) { syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", newpw.pw_name); ans = 7; goto cleanup; } } else if (useadjunct) { /* * Clear the adj_encrypt array. Extract the encrypted passwd * into adj_encrypt by setting adj_crypt_begin and * adj_crypt_end to point at the first character of the * encrypted passwd and the first character following the * encrypted passwd in adjbuf, respectively, and copy the * stuff between (there may not be anything) into adj_ecrypt. * Then, check that adj_encrypt contains something and that * the old passwd is correct. */ memset(adj_encrypt, 0, sizeof (adj_encrypt)); adj_crypt_begin = adjbuf + namelen; adj_crypt_end = strchr(adj_crypt_begin, ':'); strncpy(adj_encrypt, adj_crypt_begin, adj_crypt_end - adj_crypt_begin); oldpass_crypt = cryptoldpasswd(yppwd.oldpass, adj_encrypt, newpw.pw_name); if (oldpass_crypt == NULL) goto cleanup; if (!root_on_master && *adj_encrypt && (strcmp(oldpass_crypt, adj_encrypt) != 0)) { syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", newpw.pw_name); ans = 7; goto cleanup; } } else { oldpass_crypt = cryptoldpasswd(yppwd.oldpass, opwd.pw_passwd, newpw.pw_name); if (oldpass_crypt == NULL) goto cleanup; if (!root_on_master && opwd.pw_passwd && *opwd.pw_passwd && (strcmp(oldpass_crypt, opwd.pw_passwd) != 0)) { syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", newpw.pw_name); ans = 7; goto cleanup; } } #ifdef DEBUG printf("%d %d %d\n", chsh, chgecos, chpw); printf("%s %s %s\n", yppwd.newpw.pw_shell, yppwd.newpw.pw_gecos, yppwd.newpw.pw_passwd); printf("%s %s %s\n", opwd.pw_shell, opwd.pw_gecos, ospwd.sp_pwdp); #endif if (chsh && !validloginshell(opwd.pw_shell, newpw.pw_shell, root_on_master)) { goto cleanup; } /* security hole fix from original source */ for (p = newpw.pw_name; (*p != '\0'); p++) if ((*p == ':') || !(isprint(*p))) *p = '$'; /* you lose buckwheat */ for (p = newpw.pw_passwd; (*p != '\0'); p++) if ((*p == ':') || !(isprint(*p))) *p = '$'; /* you lose buckwheat */ if (chgecos) opwd.pw_gecos = newpw.pw_gecos; if (chsh) opwd.pw_shell = newpw.pw_shell; /* * If we're changing the shell or gecos fields and we're * using a shadow or adjunct file or not changing the passwd * then go ahead and update the passwd file. The case where * the passwd is being changed and we are not using a shadow * or adjunct file is handled later. */ if ((chsh || chgecos) && (useshadow || useadjunct || !chpw) && putpwent(&opwd, npwfp)) { syslog(LOG_ERR, "yppasswdd: putpwent failed: %s\n", passwd_file); goto cleanup; } if (chpw) { if (useshadow) { ospwd.sp_pwdp = newpw.pw_passwd; now = DAY_NOW; /* password aging - bug for bug compatibility */ if (ospwd.sp_max != -1) { if (now < ospwd.sp_lstchg + ospwd.sp_min) { syslog(LOG_ERR, "yppasswdd: Sorry: < %ld days " "since the last change.\n", ospwd.sp_min); goto cleanup; } } ospwd.sp_lstchg = now; if (putspent(&ospwd, nspfp)) { syslog(LOG_ERR, "yppasswdd: putspent failed: %s\n", shadow_file); goto cleanup; } } else if (useadjunct) { sprintf(adjbuf_new, "%s%s%s", name, newpw.pw_passwd, adj_crypt_end); if (fputs(adjbuf_new, nadjfp) == EOF) { syslog(LOG_ERR, "yppasswdd: write to adjunct failed: %s\n", adjunct_file); goto cleanup; } } else { opwd.pw_passwd = newpw.pw_passwd; if (putpwent(&opwd, npwfp)) { syslog(LOG_ERR, "yppasswdd: putpwent failed: %s\n", passwd_file); goto cleanup; } } } if (!doneflag) { doneflag = 1; goto loop_in_files; } install_files: /* * Critical section, nothing special needs to be done since we * hold exclusive access to the *.ptmp files */ fflush(npwfp); if (useshadow) fflush(nspfp); if (useadjunct) fflush(nadjfp); strcpy(tmppasswdfile, passwd_file); strcat(tmppasswdfile, "-"); if (useshadow) { strcpy(tmpshadowfile, shadow_file); strcat(tmpshadowfile, "-"); } if (useadjunct) { strcpy(tmpadjunctfile, adjunct_file); strcat(tmpadjunctfile, "-"); } if ((!useshadow && !useadjunct) || (chsh || chgecos)) { if (rename(passwd_file, tmppasswdfile) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to backup " "passwd file: %m"); goto cleanup; } else { if (rename(newpasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to mv passwd: %m"); if (rename(tmppasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of passwd file: %m"); } goto cleanup; } } } if (useshadow && chpw) { if (rename(shadow_file, tmpshadowfile) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to back up " "shadow file: %m"); if (rename(tmppasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of passwd file: %m"); } goto cleanup; } else { if (rename(newshadowfile, shadow_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to mv shadow: %m"); if (rename(tmpshadowfile, shadow_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of shadow file: %m"); } if (rename(tmppasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of passwd file: %m"); } goto cleanup; } } } else if (useadjunct && chpw) { if (rename(adjunct_file, tmpadjunctfile) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to back up " "adjunct file: %m"); if (rename(tmppasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore backup " "of passwd: %m"); } goto cleanup; } else { if (rename(newadjunctfile, adjunct_file) < 0) { syslog(LOG_CRIT, "yppassdd: failed to mv adjunct: %m"); if (rename(tmppasswdfile, passwd_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of passwd file: %m"); } if (rename(tmpadjunctfile, adjunct_file) < 0) { syslog(LOG_CRIT, "yppasswdd: failed to restore " "backup of adjunct file: %m"); } goto cleanup; } } } if (doneflag) ans = 0; /* End critical section */ /* * Here we have come only after the new files have been successfully * renamed to original files. At this point, the temp files would still * be existing we need to remove them from the /etc directory */ unlink(tmppasswdfile); if (useshadow) unlink(tmpshadowfile); if (useadjunct) unlink(tmpadjunctfile); cleanup: /* If we don't have opwfp, then we didn't do anything */ if (opwfp) { fclose(opwfp); if (ospfp) { fclose(ospfp); } if (oadjfp) { fclose(oadjfp); } unlink(newpasswdfile); /* These tests are cheaper than failing syscalls */ if (useshadow) unlink(newshadowfile); if (useadjunct) unlink(newadjunctfile); if (npwfp) { fclose(npwfp); if (nspfp) { fclose(nspfp); } if (nadjfp) { fclose(nadjfp); } } } ypulckpwdf(); if (doneflag && mflag) { retval = fork(); if (retval < 0) { syslog(LOG_ERR, "yppasswdd: Fork failed %m"); } else if (retval == 0) { strcpy(cmdbuf, "/usr/ccs/bin/make"); for (i = Mstart + 1; i < Argc; i++) { strcat(cmdbuf, " "); strcat(cmdbuf, Argv[i]); } #ifdef DEBUG syslog(LOG_ERR, "yppasswdd: about to " "execute %s\n", cmdbuf); #else if (yplckpwdf() < 0) { syslog(LOG_ERR, "yppasswdd: Couldn't get the " "lock to update the maps"); } else { setpgrp(); system(cmdbuf); ypulckpwdf(); } #endif exit(0); } } sigaction(SIGHUP, &osa1, (struct sigaction *)0); sigaction(SIGINT, &osa2, (struct sigaction *)0); sigaction(SIGQUIT, &osa3, (struct sigaction *)0); if (!svc_sendreply(transp, xdr_int, (char *)&ans)) syslog(LOG_WARNING, "yppasswdd: couldn\'t reply to RPC call\n"); }
// {{{ user_add() /// Create a valid user account void user_add(user_t *o, char *username, volatile char *passwd) { o->error[0]=0; struct passwd p; struct passwd *pw; struct spwd sp; FILE *f; int min = 1000; int max = 65000; char home[256]; snprintf(home, sizeof(home), "/home/%s", username); p.pw_name = (char *)username; p.pw_passwd = "x"; p.pw_uid = USER_DEFAULT_ID; p.pw_gid = USER_GROUP_ID; p.pw_gecos = "OpenDomo User"; p.pw_dir = home; p.pw_shell = "/bin/sh"; f = fopen("/etc/passwd", "r"); /* check user and get valid id */ while ((pw = fgetpwent(f))) { if (strcmp(pw->pw_name, p.pw_name) == 0) { sstrncpy(o->error, "user_add(): user exists", USER_ERROR_SIZE); return; } if ((pw->pw_uid >= p.pw_uid) && (pw->pw_uid < max) && (pw->pw_uid >= min)) { p.pw_uid = pw->pw_uid + 1; } } fclose(f); f = fopen("/etc/passwd", "a+"); if(!f) { sstrncpy(o->error, "user_add(): cannot open /etc/passwd",USER_ERROR_SIZE); return; } /* add to passwd */ if (putpwent(&p, f) == -1) { sstrncpy(o->error, "user_add(): putpwent() error", USER_ERROR_SIZE); return; } fclose(f); /* salt */ struct timeval tv; static char salt[40]; salt[0] = '\0'; gettimeofday (&tv, (struct timezone *) 0); strcat(salt, l64a (tv.tv_usec)); strcat(salt, l64a (tv.tv_sec + getpid () + clock ())); if (strlen (salt) > 3 + 8) salt[11] = '\0'; /* shadow */ sp.sp_namp = p.pw_name; sp.sp_pwdp = (char*)crypt((const char*)passwd, salt); sp.sp_min = 0; sp.sp_max = (10000L * DAY) / SCALE; sp.sp_lstchg = time((time_t *) 0) / SCALE; sp.sp_warn = -1; sp.sp_expire = -1; sp.sp_inact = -1; sp.sp_flag = -1; /* add to shadow */ f = fopen("/etc/shadow", "a+"); if(!f) { sstrncpy(o->error, "user_add(): cannot open /etc/shadow",USER_ERROR_SIZE); return; } if (putspent(&sp, f) == -1) { sstrncpy(o->error, "user_add(): putspent() error",USER_ERROR_SIZE); return; } fclose(f); /* Create home */ mkdir(home, 0700); chown(home, p.pw_uid, USER_GROUP_ID); }
bool KUserFiles::savesdw() { #ifdef HAVE_SHADOW bool addok = false; QString tmp; FILE *f; struct spwd *spwp; struct spwd s; KU::KUser *up; QString shadow_file = mCfg->shadowsrc(); QString new_shadow_file = shadow_file+QString::fromLatin1(KU_CREATE_EXT); if ( shadow_file.isEmpty() ) return TRUE; if (!s_backuped) { if (!backup(shadow_file)) return FALSE; s_backuped = TRUE; } if ((f = fopen(QFile::encodeName(new_shadow_file), "w")) == NULL) { KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(new_shadow_file) ); return FALSE; } s.sp_namp = (char *)malloc(200); s.sp_pwdp = (char *)malloc(200); QPtrListIterator<KU::KUser> it( mUsers ); up = (*it); while (true) { if ( up == 0 ) { if ( addok ) break; it = QPtrListIterator<KU::KUser> ( mAdd ); up = (*it); addok = true; if ( up == 0 ) break; }; if ( mDel.containsRef( up ) ) { ++it; up = (*it); continue; } if ( mMod.contains( up ) ) up = &( mMod[ up ] ); strncpy( s.sp_namp, up->getName().local8Bit(), 200 ); if ( up->getDisabled() ) strncpy( s.sp_pwdp, QString("!!" + up->getSPwd()).local8Bit(), 200 ); else strncpy( s.sp_pwdp, up->getSPwd().local8Bit(), 200 ); s.sp_lstchg = timeToDays( up->getLastChange() ); s.sp_min = up->getMin(); s.sp_max = up->getMax(); #ifndef _SCO_DS s.sp_warn = up->getWarn(); s.sp_inact = up->getInactive(); s.sp_expire = timeToDays( up->getExpire() ); s.sp_flag = up->getFlag(); #endif spwp = &s; putspent(spwp, f); ++it; up = (*it); } fclose(f); chmod(QFile::encodeName(new_shadow_file), sdw_mode); chown(QFile::encodeName(new_shadow_file), sdw_uid, sdw_gid); rename(QFile::encodeName(new_shadow_file), QFile::encodeName(shadow_file)); free(s.sp_namp); free(s.sp_pwdp); #endif // HAVE_SHADOW return TRUE; }