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; } }
// Uses fgetspent() instead of getspnam(), to guarantee that the returned user // is a local user, and not for example from LDAP. static struct spwd *GetSpEntry(const char *puser) { FILE *fptr = fopen("/etc/shadow", "r"); if (!fptr) { Log(LOG_LEVEL_ERR, "Could not open '/etc/shadow': %s", GetErrorStr()); return NULL; } struct spwd *spwd_info; bool found = false; while ((spwd_info = fgetspent(fptr))) { if (strcmp(puser, spwd_info->sp_namp) == 0) { found = true; break; } } fclose(fptr); if (found) { return spwd_info; } else { // Failure to find the user means we just set errno to zero. // Perhaps not optimal, but we cannot pass ENOENT, because the fopen might // fail for this reason, and that should not be treated the same. errno = 0; return NULL; } }
static VALUE rb_shadow_fgetspent(VALUE self, VALUE file) { struct spwd *entry; VALUE result; if( TYPE(file) != T_FILE ) rb_raise(rb_eTypeError,"argument must be a File."); entry = fgetspent(file_ptr(RFILE(file)->fptr)); if( entry == NULL ) return Qnil; result = rb_struct_new(rb_sPasswdEntry, rb_tainted_str_new2(entry->sp_namp), rb_tainted_str_new2(entry->sp_pwdp), INT2FIX(entry->sp_lstchg), INT2FIX(entry->sp_min), INT2FIX(entry->sp_max), INT2FIX(entry->sp_warn), INT2FIX(entry->sp_inact), INT2FIX(entry->sp_expire), INT2FIX(entry->sp_flag), 0); return result; };
static VALUE rb_shadow_fgetspent(VALUE self, VALUE file) { struct spwd *entry; VALUE result; if( TYPE(file) != T_FILE ) rb_raise(rb_eTypeError,"argument must be a File."); entry = fgetspent( file_ptr( (RFILE(file)->fptr) ) ); if( entry == NULL ) return Qnil; result = convert_pw_struct( entry ); return result; };
struct spwd *spwd_find(const char *spwd_path, const char *name) { struct spwd *spwd; FILE *shdwf; if (NULL == (shdwf = fopen(spwd_path, "r"))) { return NULL; } while (NULL != (spwd = fgetspent(shdwf))) { if (0 == strcmp(spwd->sp_namp, name)) { break; } } fclose(shdwf); return spwd; }
GBytes *CacheUtilReadShadowFile(const gchar *path, const gchar *username, GError **error) { struct spwd *stmpent = NULL; FILE *shadowfile = fopen(path, "r"); if (shadowfile == NULL) { g_set_error(error, UTIL_ERROR, UTIL_ERROR_NO_OPEN_FILE, "Failed to open file: %s", g_strerror(errno)); return NULL; } while ((stmpent = fgetspent(shadowfile))) { if (!strcmp(stmpent->sp_namp, username)) { // Return matching shadow hash value. GBytes* hash = g_bytes_new(stmpent->sp_pwdp, strlen(stmpent->sp_pwdp)); fclose(shadowfile); return hash; } } fclose(shadowfile); g_set_error(error, UTIL_ERROR, UTIL_ERROR_NO_HASH, "Could not find shadow hash."); return NULL; }
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; } }
struct spwd *getspent (void) { #ifdef USE_NIS int nis_1_user = 0; struct spwd *val; char buf[BUFSIZ]; #endif if (NULL == shadow) { setspent (); } #ifdef USE_NIS again: /* * See if we are reading from the local file. */ if (nis_state == native || nis_state == native2) { /* * Get the next entry from the shadow file. Return NULL * right away if there is none. */ val = fgetspent (shadow); if (NULL == val) return 0; /* * If this entry began with a NIS escape character, we have * to see if this is just a single user, or if the entire * map is being asked for. */ if (IS_NISCHAR (val->sp_namp[0])) { if (val->sp_namp[1]) nis_1_user = 1; else nis_state = start; } /* * If this isn't a NIS user and this isn't an escape to go * use a NIS map, it must be a regular local user. */ if (nis_1_user == 0 && nis_state != start) return val; /* * If this is an escape to use an NIS map, switch over to * that bunch of code. */ if (nis_state == start) goto again; /* * NEEDSWORK. Here we substitute pieces-parts of this entry. */ return 0; } else { if (!nis_bound) { if (bind_nis ()) { nis_state = native2; goto again; } } if (nis_state == start) { if (yp_first (nis_domain, "shadow.bynam", &nis_key, &nis_keylen, &nis_val, &nis_vallen)) { nis_state = native2; goto again; } nis_state = middle; } else if (nis_state == middle) { if (yp_next (nis_domain, "shadow.bynam", nis_key, nis_keylen, &nis_key, &nis_keylen, &nis_val, &nis_vallen)) { nis_state = native2; goto again; } } return my_sgetspent (nis_val); } #else return (fgetspent (shadow)); #endif }
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"); }
bool KUserFiles::loadpwd() { passwd *p; KU::KUser *tmpKU = 0; struct stat st; QString filename; QString passwd_filename; QString nispasswd_filename; int rc = 0; int passwd_errno = 0; int nispasswd_errno = 0; char processing_file = '\0'; #define P_PASSWD 0x01 #define P_NISPASSWD 0x02 #define MAXFILES 2 // Read KUser configuration passwd_filename = mCfg->passwdsrc(); nispasswd_filename = mCfg->nispasswdsrc(); // Handle unconfigured environments if(passwd_filename.isEmpty() && nispasswd_filename.isEmpty()) { mCfg->setPasswdsrc( PASSWORD_FILE ); mCfg->setGroupsrc( GROUP_FILE ); passwd_filename = mCfg->passwdsrc(); KMessageBox::error( 0, i18n("KUser sources were not configured.\nLocal passwd source set to %1\nLocal group source set to %2.").arg(mCfg->passwdsrc().arg(mCfg->groupsrc())) ); } if(!passwd_filename.isEmpty()) { processing_file = processing_file | P_PASSWD; filename.append(passwd_filename); } // Start reading passwd file(s) for(int i = 0; i < MAXFILES; i++) { rc = stat(QFile::encodeName(filename), &st); if(rc != 0) { KMessageBox::error( 0, i18n("Stat call on file %1 failed: %2\nCheck KUser settings.").arg(filename).arg(QString::fromLocal8Bit(strerror(errno))) ); if( (processing_file & P_PASSWD) != 0 ) { passwd_errno = errno; if(!nispasswd_filename.isEmpty()) { processing_file = processing_file & ~P_PASSWD; processing_file = processing_file | P_NISPASSWD; filename.truncate(0); filename.append(nispasswd_filename); } continue; } else{ nispasswd_errno = errno; break; } } pwd_mode = st.st_mode & 0666; pwd_uid = st.st_uid; pwd_gid = st.st_gid; // We are reading our configuration specified passwd file QString tmp; #ifdef HAVE_FGETPWENT FILE *fpwd = fopen(QFile::encodeName(filename), "r"); if(fpwd == NULL) { KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(filename) ); return FALSE; } while ((p = fgetpwent(fpwd)) != NULL) { #else setpwent(); //This should be enough for BSDs while ((p = getpwent()) != NULL) { #endif tmpKU = new KU::KUser(); tmpKU->setCaps( KU::KUser::Cap_POSIX ); tmpKU->setUID(p->pw_uid); tmpKU->setGID(p->pw_gid); tmpKU->setName(QString::fromLocal8Bit(p->pw_name)); tmp = QString::fromLocal8Bit( p->pw_passwd ); if ( tmp != "x" && tmp != "*" && !tmp.startsWith("!") ) tmpKU->setDisabled( false ); else tmpKU->setDisabled( true ); if ( tmp.startsWith("!") ) tmp.remove(0, 1); tmpKU->setPwd( tmp ); tmpKU->setHomeDir(QString::fromLocal8Bit(p->pw_dir)); tmpKU->setShell(QString::fromLocal8Bit(p->pw_shell)); #if defined(__FreeBSD__) || defined(__bsdi__) tmpKU->setClass(QString::fromLatin1(p->pw_class)); tmpKU->setLastChange(p->pw_change); tmpKU->setExpire(p->pw_expire); #endif if ((p->pw_gecos != 0) && (p->pw_gecos[0] != 0)) fillGecos(tmpKU, p->pw_gecos); mUsers.append(tmpKU); } // End reading passwd_filename #ifdef HAVE_FGETPWENT fclose(fpwd); #else endpwent(); #endif if((!nispasswd_filename.isEmpty()) && (nispasswd_filename != passwd_filename)) { processing_file = processing_file & ~P_PASSWD; processing_file = processing_file | P_NISPASSWD; filename.truncate(0); filename.append(nispasswd_filename); } else break; } // end of processing files, for loop if( (passwd_errno == 0) && (nispasswd_errno == 0) ) return (TRUE); if( (passwd_errno != 0) && (nispasswd_errno != 0) ) return (FALSE); else return(TRUE); } // Load shadow passwords bool KUserFiles::loadsdw() { #ifdef HAVE_SHADOW QString shadow_file,tmp; struct spwd *spw; KU::KUser *up = NULL; struct stat st; shadow_file = mCfg->shadowsrc(); if ( shadow_file.isEmpty() ) return TRUE; stat( QFile::encodeName(shadow_file), &st); sdw_mode = st.st_mode & 0666; sdw_uid = st.st_uid; sdw_gid = st.st_gid; #ifdef HAVE_FGETSPENT FILE *f; kdDebug() << "open shadow file: " << shadow_file << endl; if ((f = fopen( QFile::encodeName(shadow_file), "r")) == NULL) { KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(shadow_file) ); caps &= ~Cap_Shadow; return TRUE; } while ((spw = fgetspent( f ))) { // read a shadow password structure #else setspent(); while ((spw = getspent())) { // read a shadow password structure #endif kdDebug() << "shadow entry: " << spw->sp_namp << endl; if ((up = lookup(QString::fromLocal8Bit(spw->sp_namp))) == NULL) { KMessageBox::error( 0, i18n("No /etc/passwd entry for %1.\nEntry will be removed at the next `Save'-operation.").arg(QString::fromLocal8Bit(spw->sp_namp)) ); continue; } tmp = QString::fromLocal8Bit( spw->sp_pwdp ); if ( tmp.startsWith("!!") || tmp == "*" ) { up->setDisabled( true ); tmp.remove( 0, 2 ); } else up->setDisabled( false ); up->setSPwd( tmp ); // cp the encrypted pwd up->setLastChange( daysToTime( spw->sp_lstchg ) ); up->setMin(spw->sp_min); up->setMax(spw->sp_max); #ifndef _SCO_DS up->setWarn(spw->sp_warn); up->setInactive(spw->sp_inact); up->setExpire( daysToTime( spw->sp_expire ) ); up->setFlag(spw->sp_flag); #endif } #ifdef HAVE_FGETSPENT fclose(f); #else endspent(); #endif #endif // HAVE_SHADOW return TRUE; } // Save password file #define escstr(a,b) tmp2 = user->a(); \ tmp2.replace(':',"_"); \ tmp2.replace(',',"_"); \ user->b( tmp2 ); bool KUserFiles::savepwd() { FILE *passwd_fd = NULL; FILE *nispasswd_fd = NULL; uid_t minuid = 0; int nis_users_written = 0; uid_t tmp_uid = 0; QString s; QString s1; QString tmp, tmp2; QString passwd_filename; QString nispasswd_filename; char errors_found = '\0'; #define NOMINUID 0x01 #define NONISPASSWD 0x02 // Read KUser configuration info passwd_filename = mCfg->passwdsrc(); nispasswd_filename = mCfg->nispasswdsrc(); QString new_passwd_filename = passwd_filename + QString::fromLatin1(KU_CREATE_EXT); QString new_nispasswd_filename = nispasswd_filename+QString::fromLatin1(KU_CREATE_EXT); if( nispasswd_filename != passwd_filename ) { minuid = mCfg->nisminuid(); } // Backup file(s) if(!passwd_filename.isEmpty()) { if (!pw_backuped) { if (!backup(passwd_filename)) return FALSE; pw_backuped = TRUE; } } if(!nispasswd_filename.isEmpty() && (nispasswd_filename != passwd_filename)) { if (!pn_backuped) { if (!backup(nispasswd_filename)) return FALSE; pn_backuped = TRUE; } } // Open file(s) if(!passwd_filename.isEmpty()) { if ((passwd_fd = fopen(QFile::encodeName(new_passwd_filename),"w")) == NULL) KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(passwd_filename) ); } if(!nispasswd_filename.isEmpty() && (nispasswd_filename != passwd_filename)){ if ((nispasswd_fd = fopen(QFile::encodeName(new_nispasswd_filename),"w")) == NULL) KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(nispasswd_filename) ); } QPtrListIterator<KU::KUser> it( mUsers ); KU::KUser *user; bool addok = false; user = (*it); while (true) { if ( user == 0 ) { if ( addok ) break; it = QPtrListIterator<KU::KUser> ( mAdd ); user = (*it); addok = true; if ( user == 0 ) break; }; if ( mDel.containsRef( user ) ) { ++it; user = (*it); continue; } if ( mMod.contains( user ) ) user = &( mMod[ user ] ); tmp_uid = user->getUID(); if ( caps & Cap_Shadow ) tmp = "x"; else { tmp = user->getPwd(); if ( user->getDisabled() && tmp != "x" && tmp != "*" ) tmp = "!" + tmp; } escstr( getName, setName ); escstr( getHomeDir, setHomeDir ); escstr( getShell, setShell ); escstr( getName, setName ); escstr( getFullName, setFullName ); #if defined(__FreeBSD__) || defined(__bsdi__) escstr( getClass, setClass ); escstr( getOffice, setOffice ); escstr( getWorkPhone, setWorkPhone ); escstr( getHomePhone, setHomePhone ); s = user->getName() + ":" + tmp + ":" + QString::number( user->getUID() ) + ":" + QString::number( user->getGID() ) + ":" + user->getClass() + ":" + QString::number( user->getLastChange() ) + ":" + QString::number( user->getExpire() ) + ":"; s1 = user->getFullName() + "," + user->getOffice() + "," + user->getWorkPhone() + "," + user->getHomePhone(); #else escstr( getOffice1, setOffice1 ); escstr( getOffice2, setOffice2 ); escstr( getAddress, setAddress ); s = user->getName() + ":" + tmp + ":" + QString::number( user->getUID() ) + ":" + QString::number( user->getGID() ) + ":"; s1 = user->getFullName() + "," + user->getOffice1() + "," + user->getOffice2() + "," + user->getAddress(); #endif for (int j=(s1.length()-1); j>=0; j--) { if (s1[j] != ',') break; s1.truncate(j); } s += s1 + ":" + user->getHomeDir() + ":" + user->getShell() + "\n"; if( (nispasswd_fd != 0) && (minuid != 0) ) { if (minuid <= tmp_uid) { fputs(s.local8Bit().data(), nispasswd_fd); nis_users_written++; ++it; user = (*it); continue; } } if( (nispasswd_fd != 0) && (minuid == 0) ) { errors_found = errors_found | NOMINUID; } if( (nispasswd_fd == 0) && (minuid != 0) ) { errors_found = errors_found | NONISPASSWD; } kdDebug() << s << endl; fputs(s.local8Bit().data(), passwd_fd); ++it; user = (*it); } if(passwd_fd) { fclose(passwd_fd); chmod(QFile::encodeName(new_passwd_filename), pwd_mode); chown(QFile::encodeName(new_passwd_filename), pwd_uid, pwd_gid); rename(QFile::encodeName(new_passwd_filename), QFile::encodeName(passwd_filename)); } if(nispasswd_fd) { fclose(nispasswd_fd); chmod(QFile::encodeName(new_nispasswd_filename), pwd_mode); chown(QFile::encodeName(new_nispasswd_filename), pwd_uid, pwd_gid); rename(QFile::encodeName(new_nispasswd_filename), QFile::encodeName(nispasswd_filename)); } if( (errors_found & NOMINUID) != 0 ) { KMessageBox::error( 0, i18n("Unable to process NIS passwd file without a minimum UID specified.\nPlease update KUser settings (Files).") ); } if( (errors_found & NONISPASSWD) != 0 ) { KMessageBox::error( 0, i18n("Specifying NIS minimum UID requires NIS file(s).\nPlease update KUser settings (Files).") ); } // need to run a utility program to build /etc/passwd, /etc/pwd.db // and /etc/spwd.db from /etc/master.passwd #if defined(__FreeBSD__) || defined(__bsdi__) if (system(PWMKDB) != 0) { KMessageBox::error( 0, i18n("Unable to build password database.") ); return FALSE; } #else if( (nis_users_written > 0) || (nispasswd_filename == passwd_filename) ) { if (system(PWMKDB) != 0) { KMessageBox::error( 0, i18n("Unable to build password databases.") ); return FALSE; } } #endif return TRUE; }
/* getspent - get a (struct spwd *) from the current shadow file */ struct spwd *getspent(void) { if (!shadow) setspent(); return (fgetspent(shadow)); }