1 #include "ssh.h"
2 #include <bio.h>
3 #include <ndb.h>
4
5 char Edecode[] = "error decoding input packet";
6 char Eencode[] = "out of space encoding output packet (BUG)";
7 char Ehangup[] = "hungup connection";
8 char Ememory[] = "out of memory";
9
10 int debuglevel;
11 int doabort;
12
13 void
error(char * fmt,...)14 error(char *fmt, ...)
15 {
16 va_list arg;
17 char buf[2048];
18
19 va_start(arg, fmt);
20 vseprint(buf, buf+sizeof(buf), fmt, arg);
21 va_end(arg);
22 fprint(2, "%s: %s\n", argv0, buf);
23 if(doabort)
24 abort();
25 exits(buf);
26 }
27
28 void
debug(int level,char * fmt,...)29 debug(int level, char *fmt, ...)
30 {
31 va_list arg;
32
33 if((level&debuglevel) == 0)
34 return;
35 va_start(arg, fmt);
36 vfprint(2, fmt, arg);
37 va_end(arg);
38 }
39
40 void*
emalloc(long n)41 emalloc(long n)
42 {
43 void *a;
44
45 a = mallocz(n, 1);
46 if(a == nil)
47 error(Ememory);
48 setmalloctag(a, getcallerpc(&n));
49 return a;
50 }
51
52 void*
erealloc(void * v,long n)53 erealloc(void *v, long n)
54 {
55 v = realloc(v, n);
56 if(v == nil)
57 error(Ememory);
58 setrealloctag(v, getcallerpc(&v));
59 return v;
60 }
61
62
63 static int killpid[32];
64 static int nkillpid;
65 void
atexitkiller(void)66 atexitkiller(void)
67 {
68 int i, pid;
69
70 pid = getpid();
71 debug(DBG, "atexitkiller: nkillpid=%d mypid=%d\n", nkillpid, pid);
72 for(i=0; i<nkillpid; i++)
73 if(pid != killpid[i]){
74 debug(DBG, "killing %d\n", killpid[i]);
75 postnote(PNPROC, killpid[i], "kill");
76 }
77 }
78 void
atexitkill(int pid)79 atexitkill(int pid)
80 {
81 killpid[nkillpid++] = pid;
82 }
83
84 int
readstrnl(int fd,char * buf,int nbuf)85 readstrnl(int fd, char *buf, int nbuf)
86 {
87 int i;
88
89 for(i=0; i<nbuf; i++){
90 switch(read(fd, buf+i, 1)){
91 case -1:
92 return -1;
93 case 0:
94 werrstr("unexpected EOF");
95 return -1;
96 default:
97 if(buf[i]=='\n'){
98 buf[i] = '\0';
99 return 0;
100 }
101 break;
102 }
103 }
104 werrstr("line too long");
105 return -1;
106 }
107
108 void
calcsessid(Conn * c)109 calcsessid(Conn *c)
110 {
111 int n;
112 uchar buf[1024];
113
114 n = mptobe(c->hostkey->n, buf, sizeof buf, nil);
115 n += mptobe(c->serverkey->n, buf+n, sizeof buf-n, nil);
116 memmove(buf+n, c->cookie, COOKIELEN);
117 n += COOKIELEN;
118 md5(buf, n, c->sessid, nil);
119 }
120
121 void
sshlog(char * f,...)122 sshlog(char *f, ...)
123 {
124 char *s;
125 va_list arg;
126 Fmt fmt;
127 static int pid;
128
129 if(pid == 0)
130 pid = getpid();
131
132 va_start(arg, f);
133 va_end(arg);
134
135 if(fmtstrinit(&fmt) < 0)
136 sysfatal("fmtstrinit: %r");
137
138 fmtprint(&fmt, "[%d] ", pid);
139 fmtvprint(&fmt, f, arg);
140
141 s = fmtstrflush(&fmt);
142 if(s == nil)
143 sysfatal("fmtstrflush: %r");
144 syslog(0, "ssh", "%s", s);
145 free(s);
146 }
147
148 /*
149 * this is far too smart.
150 */
151 static int
pstrcmp(const void * a,const void * b)152 pstrcmp(const void *a, const void *b)
153 {
154 return strcmp(*(char**)a, *(char**)b);
155 }
156
157 static char*
trim(char * s)158 trim(char *s)
159 {
160 char *t;
161 int i, last, n, nf;
162 char **f;
163 char *p;
164
165 t = emalloc(strlen(s)+1);
166 t[0] = '\0';
167 n = 1;
168 for(p=s; *p; p++)
169 if(*p == ' ')
170 n++;
171 f = emalloc((n+1)*sizeof(f[0]));
172 nf = tokenize(s, f, n+1);
173 qsort(f, nf, sizeof(f[0]), pstrcmp);
174 last=-1;
175 for(i=0; i<nf; i++){
176 if(last==-1 || strcmp(f[last], f[i])!=0){
177 if(last >= 0)
178 strcat(t, ",");
179 strcat(t, f[i]);
180 last = i;
181 }
182 }
183 return t;
184 }
185
186 static void
usetuple(Conn * c,Ndbtuple * t,int scanentries)187 usetuple(Conn *c, Ndbtuple *t, int scanentries)
188 {
189 int first;
190 Ndbtuple *l, *e;
191 char *s;
192
193 first=1;
194 s = c->host;
195 for(l=t; first||l!=t; l=l->line, first=0){
196 if(scanentries){
197 for(e=l; e; e=e->entry){
198 if(strcmp(e->val, c->host) != 0 &&
199 (strcmp(e->attr, "ip")==0 || strcmp(e->attr, "dom")==0 || strcmp(e->attr, "sys")==0)){
200 s = smprint("%s %s", s, e->val);
201 if(s == nil)
202 error("out of memory");
203 }
204 }
205 }
206 if(strcmp(l->val, c->host) != 0 &&
207 (strcmp(l->attr, "ip")==0 || strcmp(l->attr, "dom")==0 || strcmp(l->attr, "sys")==0)){
208 s = smprint("%s %s", s, l->val);
209 if(s == nil)
210 error("out of memory");
211 }
212 }
213 s = trim(s);
214 c->aliases = s;
215 }
216
217 void
setaliases(Conn * c,char * name)218 setaliases(Conn *c, char *name)
219 {
220 char *p, *net;
221 char *attr[2];
222 Ndbtuple *t;
223
224 net = "/net";
225 if(name[0]=='/'){
226 p = strchr(name+1, '/');
227 if(p){
228 net = emalloc(p-name+1);
229 memmove(net, name, p-name);
230 }
231 }
232 if(p = strchr(name, '!'))
233 name = p+1;
234
235 c->host = emalloc(strlen(name)+1);
236 strcpy(c->host, name);
237
238 c->aliases = c->host;
239 attr[0] = "dom";
240 attr[1] = "ip";
241 t = csipinfo(nil, ipattr(name), name, attr, 2);
242 if(t != nil){
243 usetuple(c, t, 0);
244 ndbfree(t);
245 }else{
246 t = dnsquery(net, name, "ip");
247 if(t != nil){
248 usetuple(c, t, 1);
249 ndbfree(t);
250 }
251 }
252 }
253
254 void
privatefactotum(void)255 privatefactotum(void)
256 {
257 char *user;
258 Dir *d;
259
260 if((user=getuser()) && (d=dirstat("/mnt/factotum/rpc")) && strcmp(user, d->uid)!=0){
261 /* grab the terminal's factotum */
262 rfork(RFNAMEG); /* was RFNOTEG, which makes little sense */
263 if(access("/mnt/term/mnt/factotum", AEXIST) >= 0){
264 // fprint(2, "binding terminal's factotum\n");
265 if(bind("/mnt/term/mnt/factotum", "/mnt/factotum", MREPL) < 0)
266 sysfatal("cannot find factotum");
267 }
268 }
269 }
270