secureidcheck.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /* RFC2138 */
  2. #include <u.h>
  3. #include <libc.h>
  4. #include <ip.h>
  5. #include <ctype.h>
  6. #include <mp.h>
  7. #include <libsec.h>
  8. #include <bio.h>
  9. #include <ndb.h>
  10. #define AUTHLOG "auth"
  11. enum{ R_AccessRequest=1, /* Packet code */
  12. R_AccessAccept=2,
  13. R_AccessReject=3,
  14. R_AccessChallenge=11,
  15. R_UserName=1,
  16. R_UserPassword=2,
  17. R_NASIPAddress=4,
  18. R_ReplyMessage=18,
  19. R_State=24,
  20. R_NASIdentifier=32
  21. };
  22. typedef struct Secret{
  23. uchar *s;
  24. int len;
  25. } Secret;
  26. typedef struct Attribute{
  27. struct Attribute *next;
  28. uchar type;
  29. uchar len; // number of bytes in value
  30. uchar val[256];
  31. } Attribute;
  32. typedef struct Packet{
  33. uchar code, ID;
  34. uchar authenticator[16];
  35. Attribute first;
  36. } Packet;
  37. // assumes pass is at most 16 chars
  38. void
  39. hide(Secret *shared, uchar *auth, Secret *pass, uchar *x)
  40. {
  41. DigestState *M;
  42. int i, n = pass->len;
  43. M = md5(shared->s, shared->len, nil, nil);
  44. md5(auth, 16, x, M);
  45. if(n > 16)
  46. n = 16;
  47. for(i = 0; i < n; i++)
  48. x[i] ^= (pass->s)[i];
  49. }
  50. int
  51. authcmp(Secret *shared, uchar *buf, int m, uchar *auth)
  52. {
  53. DigestState *M;
  54. uchar x[16];
  55. M = md5(buf, 4, nil, nil); // Code+ID+Length
  56. M = md5(auth, 16, nil, M); // RequestAuth
  57. M = md5(buf+20, m-20, nil, M); // Attributes
  58. md5(shared->s, shared->len, x, M);
  59. return memcmp(x, buf+4, 16);
  60. }
  61. Packet*
  62. newRequest(uchar *auth)
  63. {
  64. static uchar ID = 0;
  65. Packet *p;
  66. p = (Packet*)malloc(sizeof(*p));
  67. if(p == nil)
  68. return nil;
  69. p->code = R_AccessRequest;
  70. p->ID = ++ID;
  71. memmove(p->authenticator, auth, 16);
  72. p->first.next = nil;
  73. p->first.type = 0;
  74. return p;
  75. }
  76. void
  77. freePacket(Packet *p)
  78. {
  79. Attribute *a, *x;
  80. if(!p)
  81. return;
  82. a = p->first.next;
  83. while(a){
  84. x = a;
  85. a = a->next;
  86. free(x);
  87. }
  88. free(p);
  89. }
  90. int
  91. ding(void*, char *msg)
  92. {
  93. syslog(0, AUTHLOG, "ding %s", msg);
  94. if(strstr(msg, "alarm"))
  95. return 1;
  96. return 0;
  97. }
  98. Packet *
  99. rpc(char *dest, Secret *shared, Packet *req)
  100. {
  101. uchar buf[4096], buf2[4096], *b, *e;
  102. Packet *resp;
  103. Attribute *a;
  104. int m, n, fd, try;
  105. // marshal request
  106. e = buf + sizeof buf;
  107. buf[0] = req->code;
  108. buf[1] = req->ID;
  109. memmove(buf+4, req->authenticator, 16);
  110. b = buf+20;
  111. for(a = &req->first; a; a = a->next){
  112. if(b + 2 + a->len > e)
  113. return nil;
  114. *b++ = a->type;
  115. *b++ = 2 + a->len;
  116. memmove(b, a->val, a->len);
  117. b += a->len;
  118. }
  119. n = b-buf;
  120. buf[2] = n>>8;
  121. buf[3] = n;
  122. // send request, wait for reply
  123. fd = dial(dest, 0, 0, 0);
  124. if(fd < 0){
  125. syslog(0, AUTHLOG, "%s: rpc can't get udp channel", dest);
  126. return nil;
  127. }
  128. atnotify(ding, 1);
  129. m = -1;
  130. for(try = 0; try < 2; try++){
  131. alarm(4000);
  132. m = write(fd, buf, n);
  133. if(m != n){
  134. syslog(0, AUTHLOG, "%s: rpc write err %d %d: %r", dest, m, n);
  135. m = -1;
  136. break;
  137. }
  138. m = read(fd, buf2, sizeof buf2);
  139. alarm(0);
  140. if(m < 0){
  141. syslog(0, AUTHLOG, "%s rpc read err %d: %r", dest, m);
  142. break; // failure
  143. }
  144. if(m == 0 || buf2[1] != buf[1]){ // need matching ID
  145. syslog(0, AUTHLOG, "%s unmatched reply %d", dest, m);
  146. continue;
  147. }
  148. if(authcmp(shared, buf2, m, buf+4) == 0)
  149. break;
  150. syslog(0, AUTHLOG, "%s bad rpc chksum", dest);
  151. }
  152. close(fd);
  153. if(m <= 0)
  154. return nil;
  155. // unmarshal reply
  156. b = buf2;
  157. e = buf2+m;
  158. resp = (Packet*)malloc(sizeof(*resp));
  159. if(resp == nil)
  160. return nil;
  161. resp->code = *b++;
  162. resp->ID = *b++;
  163. n = *b++;
  164. n = (n<<8) | *b++;
  165. if(m != n){
  166. syslog(0, AUTHLOG, "rpc got %d bytes, length said %d", m, n);
  167. if(m > n)
  168. e = buf2+n;
  169. }
  170. memmove(resp->authenticator, b, 16);
  171. b += 16;
  172. a = &resp->first;
  173. a->type = 0;
  174. while(1){
  175. if(b >= e){
  176. a->next = nil;
  177. break; // exit loop
  178. }
  179. a->type = *b++;
  180. a->len = (*b++) - 2;
  181. if(b + a->len > e){ // corrupt packet
  182. a->next = nil;
  183. freePacket(resp);
  184. return nil;
  185. }
  186. memmove(a->val, b, a->len);
  187. b += a->len;
  188. if(b < e){ // any more attributes?
  189. a->next = (Attribute*)malloc(sizeof(*a));
  190. if(a->next == nil){
  191. free(req);
  192. return nil;
  193. }
  194. a = a->next;
  195. }
  196. }
  197. return resp;
  198. }
  199. int
  200. setAttribute(Packet *p, uchar type, uchar *s, int n)
  201. {
  202. Attribute *a;
  203. a = &p->first;
  204. if(a->type != 0){
  205. a = (Attribute*)malloc(sizeof(*a));
  206. if(a == nil)
  207. return -1;
  208. a->next = p->first.next;
  209. p->first.next = a;
  210. }
  211. a->type = type;
  212. a->len = n;
  213. if(a->len > 253 ) // RFC2138, section 5
  214. a->len = 253;
  215. memmove(a->val, s, a->len);
  216. return 0;
  217. }
  218. /* return a reply message attribute string */
  219. char*
  220. replymsg(Packet *p)
  221. {
  222. Attribute *a;
  223. static char buf[255];
  224. for(a = &p->first; a; a = a->next){
  225. if(a->type == R_ReplyMessage){
  226. if(a->len >= sizeof buf)
  227. a->len = sizeof(buf)-1;
  228. memmove(buf, a->val, a->len);
  229. buf[a->len] = 0;
  230. }
  231. }
  232. return buf;
  233. }
  234. /* for convenience while debugging */
  235. char *replymess;
  236. Attribute *stateattr;
  237. void
  238. logPacket(Packet *p)
  239. {
  240. Attribute *a;
  241. char buf[255];
  242. char pbuf[4*1024];
  243. uchar *au = p->authenticator;
  244. int i;
  245. char *np, *e;
  246. e = pbuf + sizeof(pbuf);
  247. np = seprint(pbuf, e, "Packet ID=%d auth=%x %x %x... ", p->ID, au[0], au[1], au[2]);
  248. switch(p->code){
  249. case R_AccessRequest:
  250. np = seprint(np, e, "request\n");
  251. break;
  252. case R_AccessAccept:
  253. np = seprint(np, e, "accept\n");
  254. break;
  255. case R_AccessReject:
  256. np = seprint(np, e, "reject\n");
  257. break;
  258. case R_AccessChallenge:
  259. np = seprint(np, e, "challenge\n");
  260. break;
  261. default:
  262. np = seprint(np, e, "code=%d\n", p->code);
  263. break;
  264. }
  265. replymess = "0000000";
  266. for(a = &p->first; a; a = a->next){
  267. if(a->len > 253 )
  268. a->len = 253;
  269. memmove(buf, a->val, a->len);
  270. np = seprint(np, e, " [%d]", a->type);
  271. for(i = 0; i<a->len; i++)
  272. if(isprint(a->val[i]))
  273. np = seprint(np, e, "%c", a->val[i]);
  274. else
  275. np = seprint(np, e, "\\%o", a->val[i]);
  276. np = seprint(np, e, "\n");
  277. buf[a->len] = 0;
  278. if(a->type == R_ReplyMessage)
  279. replymess = strdup(buf);
  280. else if(a->type == R_State)
  281. stateattr = a;
  282. }
  283. syslog(0, AUTHLOG, "%s", pbuf);
  284. }
  285. static uchar*
  286. getipv4addr(void)
  287. {
  288. Ipifc *nifc;
  289. Iplifc *lifc;
  290. static Ipifc *ifc;
  291. ifc = readipifc("/net", ifc, -1);
  292. for(nifc = ifc; nifc; nifc = nifc->next)
  293. for(lifc = nifc->lifc; lifc; lifc = lifc->next)
  294. if(ipcmp(lifc->ip, IPnoaddr) != 0 && ipcmp(lifc->ip, v4prefix) != 0)
  295. return lifc->ip;
  296. return nil;
  297. }
  298. extern Ndb *db;
  299. /* returns 1 on success, 0 on failure */
  300. char*
  301. secureidcheck(char *user, char *response)
  302. {
  303. Packet *req = nil, *resp = nil;
  304. ulong u[4];
  305. uchar x[16];
  306. char radiussecret[Ndbvlen];
  307. char ruser[Ndbvlen];
  308. char dest[3*IPaddrlen+20];
  309. Secret shared, pass;
  310. char *rv = "authentication failed";
  311. Ndbs s;
  312. Ndbtuple *t, *nt, *tt;
  313. uchar *ip;
  314. /* bad responses make them disable the fob, avoid silly checks */
  315. if(strlen(response) < 4 || strpbrk(response,"abcdefABCDEF") != nil)
  316. goto out;
  317. /* get radius secret */
  318. t = ndbgetval(db, &s, "radius", "lra-radius", "secret", radiussecret);
  319. if(t == nil){
  320. syslog(0, AUTHLOG, "secureidcheck: nil radius secret: %r");
  321. goto out;
  322. }
  323. /* translate user name if we have to */
  324. strcpy(ruser, user);
  325. for(nt = t; nt; nt = nt->entry){
  326. if(strcmp(nt->attr, "uid") == 0 && strcmp(nt->val, user) == 0)
  327. for(tt = nt->line; tt != nt; tt = tt->line)
  328. if(strcmp(tt->attr, "rid") == 0){
  329. strcpy(ruser, tt->val);
  330. break;
  331. }
  332. }
  333. ndbfree(t);
  334. u[0] = fastrand();
  335. u[1] = fastrand();
  336. u[2] = fastrand();
  337. u[3] = fastrand();
  338. req = newRequest((uchar*)u);
  339. if(req == nil)
  340. goto out;
  341. shared.s = (uchar*)radiussecret;
  342. shared.len = strlen(radiussecret);
  343. ip = getipv4addr();
  344. if(ip == nil){
  345. syslog(0, AUTHLOG, "no interfaces: %r\n");
  346. goto out;
  347. }
  348. if(setAttribute(req, R_NASIPAddress, ip + IPv4off, 4) < 0)
  349. goto out;
  350. if(setAttribute(req, R_UserName, (uchar*)ruser, strlen(ruser)) < 0)
  351. goto out;
  352. pass.s = (uchar*)response;
  353. pass.len = strlen(response);
  354. hide(&shared, req->authenticator, &pass, x);
  355. if(setAttribute(req, R_UserPassword, x, 16) < 0)
  356. goto out;
  357. t = ndbsearch(db, &s, "sys", "lra-radius");
  358. if(t == nil){
  359. syslog(0, AUTHLOG, "secureidcheck: nil radius sys search: %r\n");
  360. goto out;
  361. }
  362. for(nt = t; nt; nt = nt->entry){
  363. if(strcmp(nt->attr, "ip") != 0)
  364. continue;
  365. snprint(dest,sizeof dest,"udp!%s!oradius", nt->val);
  366. resp = rpc(dest, &shared, req);
  367. if(resp == nil){
  368. syslog(0, AUTHLOG, "%s nil response", dest);
  369. continue;
  370. }
  371. if(resp->ID != req->ID){
  372. syslog(0, AUTHLOG, "%s mismatched ID req=%d resp=%d",
  373. dest, req->ID, resp->ID);
  374. freePacket(resp);
  375. resp = nil;
  376. continue;
  377. }
  378. switch(resp->code){
  379. case R_AccessAccept:
  380. syslog(0, AUTHLOG, "%s accepted ruser=%s", dest, ruser);
  381. rv = nil;
  382. break;
  383. case R_AccessReject:
  384. syslog(0, AUTHLOG, "%s rejected ruser=%s %s", dest, ruser, replymsg(resp));
  385. rv = "secureid failed";
  386. break;
  387. case R_AccessChallenge:
  388. syslog(0, AUTHLOG, "%s challenge ruser=%s %s", dest, ruser, replymsg(resp));
  389. rv = "secureid out of sync";
  390. break;
  391. default:
  392. syslog(0, AUTHLOG, "%s code=%d ruser=%s %s", dest, resp->code, ruser, replymsg(resp));
  393. break;
  394. }
  395. break; // we have a proper reply, no need to ask again
  396. }
  397. ndbfree(t);
  398. out:
  399. freePacket(req);
  400. freePacket(resp);
  401. return rv;
  402. }