kerberos.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. #include "kerberos.h"
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include "worker.h"
  5. #include "kerberos_context.h"
  6. #ifndef ARRAY_SIZE
  7. # define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
  8. #endif
  9. void die(const char *message) {
  10. if(errno) {
  11. perror(message);
  12. } else {
  13. printf("ERROR: %s\n", message);
  14. }
  15. exit(1);
  16. }
  17. // Call structs
  18. typedef struct AuthGSSClientCall {
  19. uint32_t flags;
  20. char *uri;
  21. char *credentials_cache;
  22. } AuthGSSClientCall;
  23. typedef struct AuthGSSClientStepCall {
  24. KerberosContext *context;
  25. char *challenge;
  26. } AuthGSSClientStepCall;
  27. typedef struct AuthGSSClientUnwrapCall {
  28. KerberosContext *context;
  29. char *challenge;
  30. } AuthGSSClientUnwrapCall;
  31. typedef struct AuthGSSClientWrapCall {
  32. KerberosContext *context;
  33. char *challenge;
  34. char *user_name;
  35. } AuthGSSClientWrapCall;
  36. typedef struct AuthGSSClientCleanCall {
  37. KerberosContext *context;
  38. } AuthGSSClientCleanCall;
  39. typedef struct AuthGSSServerInitCall {
  40. char *service;
  41. bool constrained_delegation;
  42. char *username;
  43. } AuthGSSServerInitCall;
  44. typedef struct AuthGSSServerCleanCall {
  45. KerberosContext *context;
  46. } AuthGSSServerCleanCall;
  47. typedef struct AuthGSSServerStepCall {
  48. KerberosContext *context;
  49. char *auth_data;
  50. } AuthGSSServerStepCall;
  51. typedef struct AuthUserKrb5PasswordCall {
  52. char *username;
  53. char *password;
  54. char *service;
  55. } AuthUserKrb5PasswordCall;
  56. Kerberos::Kerberos() : Nan::ObjectWrap() {
  57. }
  58. Nan::Persistent<FunctionTemplate> Kerberos::constructor_template;
  59. void Kerberos::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
  60. // Grab the scope of the call from Node
  61. Nan::HandleScope scope;
  62. // Define a new function template
  63. Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
  64. t->InstanceTemplate()->SetInternalFieldCount(1);
  65. t->SetClassName(Nan::New<String>("Kerberos").ToLocalChecked());
  66. // Set up method for the Kerberos instance
  67. Nan::SetPrototypeMethod(t, "authGSSClientInit", AuthGSSClientInit);
  68. Nan::SetPrototypeMethod(t, "authGSSClientStep", AuthGSSClientStep);
  69. Nan::SetPrototypeMethod(t, "authGSSClientUnwrap", AuthGSSClientUnwrap);
  70. Nan::SetPrototypeMethod(t, "authGSSClientWrap", AuthGSSClientWrap);
  71. Nan::SetPrototypeMethod(t, "authGSSClientClean", AuthGSSClientClean);
  72. Nan::SetPrototypeMethod(t, "authGSSServerInit", AuthGSSServerInit);
  73. Nan::SetPrototypeMethod(t, "authGSSServerClean", AuthGSSServerClean);
  74. Nan::SetPrototypeMethod(t, "authGSSServerStep", AuthGSSServerStep);
  75. Nan::SetPrototypeMethod(t, "authUserKrb5Password", AuthUserKrb5Password);
  76. constructor_template.Reset(t);
  77. // Set the symbol
  78. target->ForceSet(Nan::New<String>("Kerberos").ToLocalChecked(), t->GetFunction());
  79. }
  80. NAN_METHOD(Kerberos::New) {
  81. // Create a Kerberos instance
  82. Kerberos *kerberos = new Kerberos();
  83. // Return the kerberos object
  84. kerberos->Wrap(info.This());
  85. info.GetReturnValue().Set(info.This());
  86. }
  87. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  88. // authGSSClientInit
  89. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  90. static void _authGSSClientInit(Worker *worker) {
  91. gss_client_state *state;
  92. gss_client_response *response;
  93. // Allocate state
  94. state = (gss_client_state *)malloc(sizeof(gss_client_state));
  95. if(state == NULL) die("Memory allocation failed");
  96. // Unpack the parameter data struct
  97. AuthGSSClientCall *call = (AuthGSSClientCall *)worker->parameters;
  98. // Start the kerberos client
  99. response = authenticate_gss_client_init(call->uri, call->flags, call->credentials_cache, state);
  100. // Release the parameter struct memory
  101. free(call->uri);
  102. free(call->credentials_cache);
  103. free(call);
  104. // If we have an error mark worker as having had an error
  105. if(response->return_code == AUTH_GSS_ERROR) {
  106. worker->error = TRUE;
  107. worker->error_code = response->return_code;
  108. worker->error_message = response->message;
  109. free(state);
  110. } else {
  111. worker->return_value = state;
  112. }
  113. // Free structure
  114. free(response);
  115. }
  116. static Local<Value> _map_authGSSClientInit(Worker *worker) {
  117. KerberosContext *context = KerberosContext::New();
  118. context->state = (gss_client_state *)worker->return_value;
  119. return context->handle();
  120. }
  121. // Initialize method
  122. NAN_METHOD(Kerberos::AuthGSSClientInit) {
  123. const char *usage = "Requires a service string uri, integer flags, string credentialsCache and a callback function";
  124. // Ensure valid call
  125. if(info.Length() != 4) return Nan::ThrowError(usage);
  126. if(!info[0]->IsString() || !info[1]->IsInt32() || !info[2]->IsString() || !info[3]->IsFunction())
  127. return Nan::ThrowError(usage);
  128. Local<String> service = info[0]->ToString();
  129. // Convert uri string to c-string
  130. char *service_str = (char *)calloc(service->Utf8Length() + 1, sizeof(char));
  131. if(service_str == NULL) die("Memory allocation failed");
  132. // Write v8 string to c-string
  133. service->WriteUtf8(service_str);
  134. Local<String> credentialsCache = info[2]->ToString();
  135. // Convert string to c-string
  136. char *credentials_cache_str = (char *)calloc(credentialsCache->Utf8Length() + 1, sizeof(char));
  137. if(credentials_cache_str == NULL) die("Memory allocation failed");
  138. // Write v8 string to c-string
  139. credentialsCache->WriteUtf8(credentials_cache_str);
  140. // Allocate a structure
  141. AuthGSSClientCall *call = (AuthGSSClientCall *)calloc(1, sizeof(AuthGSSClientCall));
  142. if(call == NULL) die("Memory allocation failed");
  143. call->flags =info[1]->ToInt32()->Uint32Value();
  144. call->uri = service_str;
  145. call->credentials_cache = credentials_cache_str;
  146. // Unpack the callback
  147. Local<Function> callbackHandle = Local<Function>::Cast(info[3]);
  148. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  149. // Let's allocate some space
  150. Worker *worker = new Worker();
  151. worker->error = false;
  152. worker->request.data = worker;
  153. worker->callback = callback;
  154. worker->parameters = call;
  155. worker->execute = _authGSSClientInit;
  156. worker->mapper = _map_authGSSClientInit;
  157. // Schedule the worker with lib_uv
  158. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  159. // Return no value as it's callback based
  160. info.GetReturnValue().Set(Nan::Undefined());
  161. }
  162. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  163. // authGSSClientStep
  164. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  165. static void _authGSSClientStep(Worker *worker) {
  166. gss_client_state *state;
  167. gss_client_response *response;
  168. char *challenge;
  169. // Unpack the parameter data struct
  170. AuthGSSClientStepCall *call = (AuthGSSClientStepCall *)worker->parameters;
  171. // Get the state
  172. state = call->context->state;
  173. challenge = call->challenge;
  174. // Check what kind of challenge we have
  175. if(call->challenge == NULL) {
  176. challenge = (char *)"";
  177. }
  178. // Perform authentication step
  179. response = authenticate_gss_client_step(state, challenge);
  180. // If we have an error mark worker as having had an error
  181. if(response->return_code == AUTH_GSS_ERROR) {
  182. worker->error = TRUE;
  183. worker->error_code = response->return_code;
  184. worker->error_message = response->message;
  185. } else {
  186. worker->return_code = response->return_code;
  187. }
  188. // Free up structure
  189. if(call->challenge != NULL) free(call->challenge);
  190. free(call);
  191. free(response);
  192. }
  193. static Local<Value> _map_authGSSClientStep(Worker *worker) {
  194. Nan::HandleScope scope;
  195. // Return the return code
  196. return Nan::New<Int32>(worker->return_code);
  197. }
  198. // Initialize method
  199. NAN_METHOD(Kerberos::AuthGSSClientStep) {
  200. // Ensure valid call
  201. if(info.Length() != 2 && info.Length() != 3) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  202. if(info.Length() == 2 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsFunction())) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  203. if(info.Length() == 3 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsString() || !info[2]->IsFunction())) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  204. // Challenge string
  205. char *challenge_str = NULL;
  206. // Let's unpack the parameters
  207. Local<Object> object = info[0]->ToObject();
  208. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  209. if (!kerberos_context->IsClientInstance()) {
  210. return Nan::ThrowError("GSS context is not a client instance");
  211. }
  212. int callbackArg = 1;
  213. // If we have a challenge string
  214. if(info.Length() == 3) {
  215. // Unpack the challenge string
  216. Local<String> challenge = info[1]->ToString();
  217. // Convert uri string to c-string
  218. challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char));
  219. if(challenge_str == NULL) die("Memory allocation failed");
  220. // Write v8 string to c-string
  221. challenge->WriteUtf8(challenge_str);
  222. callbackArg = 2;
  223. }
  224. // Allocate a structure
  225. AuthGSSClientStepCall *call = (AuthGSSClientStepCall *)calloc(1, sizeof(AuthGSSClientStepCall));
  226. if(call == NULL) die("Memory allocation failed");
  227. call->context = kerberos_context;
  228. call->challenge = challenge_str;
  229. // Unpack the callback
  230. Local<Function> callbackHandle = Local<Function>::Cast(info[callbackArg]);
  231. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  232. // Let's allocate some space
  233. Worker *worker = new Worker();
  234. worker->error = false;
  235. worker->request.data = worker;
  236. worker->callback = callback;
  237. worker->parameters = call;
  238. worker->execute = _authGSSClientStep;
  239. worker->mapper = _map_authGSSClientStep;
  240. // Schedule the worker with lib_uv
  241. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  242. // Return no value as it's callback based
  243. info.GetReturnValue().Set(Nan::Undefined());
  244. }
  245. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  246. // authGSSClientUnwrap
  247. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  248. static void _authGSSClientUnwrap(Worker *worker) {
  249. gss_client_response *response;
  250. char *challenge;
  251. // Unpack the parameter data struct
  252. AuthGSSClientUnwrapCall *call = (AuthGSSClientUnwrapCall *)worker->parameters;
  253. challenge = call->challenge;
  254. // Check what kind of challenge we have
  255. if(call->challenge == NULL) {
  256. challenge = (char *)"";
  257. }
  258. // Perform authentication step
  259. response = authenticate_gss_client_unwrap(call->context->state, challenge);
  260. // If we have an error mark worker as having had an error
  261. if(response->return_code == AUTH_GSS_ERROR) {
  262. worker->error = TRUE;
  263. worker->error_code = response->return_code;
  264. worker->error_message = response->message;
  265. } else {
  266. worker->return_code = response->return_code;
  267. }
  268. // Free up structure
  269. if(call->challenge != NULL) free(call->challenge);
  270. free(call);
  271. free(response);
  272. }
  273. static Local<Value> _map_authGSSClientUnwrap(Worker *worker) {
  274. Nan::HandleScope scope;
  275. // Return the return code
  276. return Nan::New<Int32>(worker->return_code);
  277. }
  278. // Initialize method
  279. NAN_METHOD(Kerberos::AuthGSSClientUnwrap) {
  280. // Ensure valid call
  281. if(info.Length() != 2 && info.Length() != 3) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  282. if(info.Length() == 2 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsFunction())) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  283. if(info.Length() == 3 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsString() || !info[2]->IsFunction())) return Nan::ThrowError("Requires a GSS context, optional challenge string and callback function");
  284. // Challenge string
  285. char *challenge_str = NULL;
  286. // Let's unpack the parameters
  287. Local<Object> object = info[0]->ToObject();
  288. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  289. if (!kerberos_context->IsClientInstance()) {
  290. return Nan::ThrowError("GSS context is not a client instance");
  291. }
  292. // If we have a challenge string
  293. if(info.Length() == 3) {
  294. // Unpack the challenge string
  295. Local<String> challenge = info[1]->ToString();
  296. // Convert uri string to c-string
  297. challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char));
  298. if(challenge_str == NULL) die("Memory allocation failed");
  299. // Write v8 string to c-string
  300. challenge->WriteUtf8(challenge_str);
  301. }
  302. // Allocate a structure
  303. AuthGSSClientUnwrapCall *call = (AuthGSSClientUnwrapCall *)calloc(1, sizeof(AuthGSSClientUnwrapCall));
  304. if(call == NULL) die("Memory allocation failed");
  305. call->context = kerberos_context;
  306. call->challenge = challenge_str;
  307. // Unpack the callback
  308. Local<Function> callbackHandle = info.Length() == 3 ? Local<Function>::Cast(info[2]) : Local<Function>::Cast(info[1]);
  309. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  310. // Let's allocate some space
  311. Worker *worker = new Worker();
  312. worker->error = false;
  313. worker->request.data = worker;
  314. worker->callback = callback;
  315. worker->parameters = call;
  316. worker->execute = _authGSSClientUnwrap;
  317. worker->mapper = _map_authGSSClientUnwrap;
  318. // Schedule the worker with lib_uv
  319. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  320. // Return no value as it's callback based
  321. info.GetReturnValue().Set(Nan::Undefined());
  322. }
  323. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  324. // authGSSClientWrap
  325. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  326. static void _authGSSClientWrap(Worker *worker) {
  327. gss_client_response *response;
  328. char *user_name = NULL;
  329. // Unpack the parameter data struct
  330. AuthGSSClientWrapCall *call = (AuthGSSClientWrapCall *)worker->parameters;
  331. user_name = call->user_name;
  332. // Check what kind of challenge we have
  333. if(call->user_name == NULL) {
  334. user_name = (char *)"";
  335. }
  336. // Perform authentication step
  337. response = authenticate_gss_client_wrap(call->context->state, call->challenge, user_name);
  338. // If we have an error mark worker as having had an error
  339. if(response->return_code == AUTH_GSS_ERROR) {
  340. worker->error = TRUE;
  341. worker->error_code = response->return_code;
  342. worker->error_message = response->message;
  343. } else {
  344. worker->return_code = response->return_code;
  345. }
  346. // Free up structure
  347. if(call->challenge != NULL) free(call->challenge);
  348. if(call->user_name != NULL) free(call->user_name);
  349. free(call);
  350. free(response);
  351. }
  352. static Local<Value> _map_authGSSClientWrap(Worker *worker) {
  353. Nan::HandleScope scope;
  354. // Return the return code
  355. return Nan::New<Int32>(worker->return_code);
  356. }
  357. // Initialize method
  358. NAN_METHOD(Kerberos::AuthGSSClientWrap) {
  359. // Ensure valid call
  360. if(info.Length() != 3 && info.Length() != 4) return Nan::ThrowError("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function");
  361. if(info.Length() == 3 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsString() || !info[2]->IsFunction())) return Nan::ThrowError("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function");
  362. if(info.Length() == 4 && (!KerberosContext::HasInstance(info[0]) || !info[1]->IsString() || !info[2]->IsString() || !info[3]->IsFunction())) return Nan::ThrowError("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function");
  363. // Challenge string
  364. char *challenge_str = NULL;
  365. char *user_name_str = NULL;
  366. // Let's unpack the kerberos context
  367. Local<Object> object = info[0]->ToObject();
  368. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  369. if (!kerberos_context->IsClientInstance()) {
  370. return Nan::ThrowError("GSS context is not a client instance");
  371. }
  372. // Unpack the challenge string
  373. Local<String> challenge = info[1]->ToString();
  374. // Convert uri string to c-string
  375. challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char));
  376. if(challenge_str == NULL) die("Memory allocation failed");
  377. // Write v8 string to c-string
  378. challenge->WriteUtf8(challenge_str);
  379. // If we have a user string
  380. if(info.Length() == 4) {
  381. // Unpack user name
  382. Local<String> user_name = info[2]->ToString();
  383. // Convert uri string to c-string
  384. user_name_str = (char *)calloc(user_name->Utf8Length() + 1, sizeof(char));
  385. if(user_name_str == NULL) die("Memory allocation failed");
  386. // Write v8 string to c-string
  387. user_name->WriteUtf8(user_name_str);
  388. }
  389. // Allocate a structure
  390. AuthGSSClientWrapCall *call = (AuthGSSClientWrapCall *)calloc(1, sizeof(AuthGSSClientWrapCall));
  391. if(call == NULL) die("Memory allocation failed");
  392. call->context = kerberos_context;
  393. call->challenge = challenge_str;
  394. call->user_name = user_name_str;
  395. // Unpack the callback
  396. Local<Function> callbackHandle = info.Length() == 4 ? Local<Function>::Cast(info[3]) : Local<Function>::Cast(info[2]);
  397. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  398. // Let's allocate some space
  399. Worker *worker = new Worker();
  400. worker->error = false;
  401. worker->request.data = worker;
  402. worker->callback = callback;
  403. worker->parameters = call;
  404. worker->execute = _authGSSClientWrap;
  405. worker->mapper = _map_authGSSClientWrap;
  406. // Schedule the worker with lib_uv
  407. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  408. // Return no value as it's callback based
  409. info.GetReturnValue().Set(Nan::Undefined());
  410. }
  411. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  412. // authGSSClientClean
  413. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  414. static void _authGSSClientClean(Worker *worker) {
  415. gss_client_response *response;
  416. // Unpack the parameter data struct
  417. AuthGSSClientCleanCall *call = (AuthGSSClientCleanCall *)worker->parameters;
  418. // Perform authentication step
  419. response = authenticate_gss_client_clean(call->context->state);
  420. // If we have an error mark worker as having had an error
  421. if(response->return_code == AUTH_GSS_ERROR) {
  422. worker->error = TRUE;
  423. worker->error_code = response->return_code;
  424. worker->error_message = response->message;
  425. } else {
  426. worker->return_code = response->return_code;
  427. }
  428. // Free up structure
  429. free(call);
  430. free(response);
  431. }
  432. static Local<Value> _map_authGSSClientClean(Worker *worker) {
  433. Nan::HandleScope scope;
  434. // Return the return code
  435. return Nan::New<Int32>(worker->return_code);
  436. }
  437. // Initialize method
  438. NAN_METHOD(Kerberos::AuthGSSClientClean) {
  439. // Ensure valid call
  440. if(info.Length() != 2) return Nan::ThrowError("Requires a GSS context and callback function");
  441. if(!KerberosContext::HasInstance(info[0]) || !info[1]->IsFunction()) return Nan::ThrowError("Requires a GSS context and callback function");
  442. // Let's unpack the kerberos context
  443. Local<Object> object = info[0]->ToObject();
  444. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  445. if (!kerberos_context->IsClientInstance()) {
  446. return Nan::ThrowError("GSS context is not a client instance");
  447. }
  448. // Allocate a structure
  449. AuthGSSClientCleanCall *call = (AuthGSSClientCleanCall *)calloc(1, sizeof(AuthGSSClientCleanCall));
  450. if(call == NULL) die("Memory allocation failed");
  451. call->context = kerberos_context;
  452. // Unpack the callback
  453. Local<Function> callbackHandle = Local<Function>::Cast(info[1]);
  454. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  455. // Let's allocate some space
  456. Worker *worker = new Worker();
  457. worker->error = false;
  458. worker->request.data = worker;
  459. worker->callback = callback;
  460. worker->parameters = call;
  461. worker->execute = _authGSSClientClean;
  462. worker->mapper = _map_authGSSClientClean;
  463. // Schedule the worker with lib_uv
  464. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  465. // Return no value as it's callback based
  466. info.GetReturnValue().Set(Nan::Undefined());
  467. }
  468. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  469. // authGSSServerInit
  470. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  471. static void _authGSSServerInit(Worker *worker) {
  472. gss_server_state *state;
  473. gss_client_response *response;
  474. // Allocate state
  475. state = (gss_server_state *)malloc(sizeof(gss_server_state));
  476. if(state == NULL) die("Memory allocation failed");
  477. // Unpack the parameter data struct
  478. AuthGSSServerInitCall *call = (AuthGSSServerInitCall *)worker->parameters;
  479. // Start the kerberos service
  480. response = authenticate_gss_server_init(call->service, call->constrained_delegation, call->username, state);
  481. // Release the parameter struct memory
  482. free(call->service);
  483. free(call->username);
  484. free(call);
  485. // If we have an error mark worker as having had an error
  486. if(response->return_code == AUTH_GSS_ERROR) {
  487. worker->error = TRUE;
  488. worker->error_code = response->return_code;
  489. worker->error_message = response->message;
  490. free(state);
  491. } else {
  492. worker->return_value = state;
  493. }
  494. // Free structure
  495. free(response);
  496. }
  497. static Local<Value> _map_authGSSServerInit(Worker *worker) {
  498. KerberosContext *context = KerberosContext::New();
  499. context->server_state = (gss_server_state *)worker->return_value;
  500. return context->handle();
  501. }
  502. // Server Initialize method
  503. NAN_METHOD(Kerberos::AuthGSSServerInit) {
  504. // Ensure valid call
  505. if(info.Length() != 4) return Nan::ThrowError("Requires a service string, constrained delegation boolean, a username string (or NULL) for S4U2Self protocol transition and a callback function");
  506. if(!info[0]->IsString() ||
  507. !info[1]->IsBoolean() ||
  508. !(info[2]->IsString() || info[2]->IsNull()) ||
  509. !info[3]->IsFunction()
  510. ) return Nan::ThrowError("Requires a service string, constrained delegation boolean, a username string (or NULL) for S4U2Self protocol transition and a callback function");
  511. if (!info[1]->BooleanValue() && !info[2]->IsNull()) return Nan::ThrowError("S4U2Self only possible when constrained delegation is enabled");
  512. // Allocate a structure
  513. AuthGSSServerInitCall *call = (AuthGSSServerInitCall *)calloc(1, sizeof(AuthGSSServerInitCall));
  514. if(call == NULL) die("Memory allocation failed");
  515. Local<String> service = info[0]->ToString();
  516. // Convert service string to c-string
  517. char *service_str = (char *)calloc(service->Utf8Length() + 1, sizeof(char));
  518. if(service_str == NULL) die("Memory allocation failed");
  519. // Write v8 string to c-string
  520. service->WriteUtf8(service_str);
  521. call->service = service_str;
  522. call->constrained_delegation = info[1]->BooleanValue();
  523. if (info[2]->IsNull())
  524. {
  525. call->username = NULL;
  526. }
  527. else
  528. {
  529. Local<String> tmpString = info[2]->ToString();
  530. char *tmpCstr = (char *)calloc(tmpString->Utf8Length() + 1, sizeof(char));
  531. if(tmpCstr == NULL) die("Memory allocation failed");
  532. tmpString->WriteUtf8(tmpCstr);
  533. call->username = tmpCstr;
  534. }
  535. // Unpack the callback
  536. Local<Function> callbackHandle = Local<Function>::Cast(info[3]);
  537. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  538. // Let's allocate some space
  539. Worker *worker = new Worker();
  540. worker->error = false;
  541. worker->request.data = worker;
  542. worker->callback = callback;
  543. worker->parameters = call;
  544. worker->execute = _authGSSServerInit;
  545. worker->mapper = _map_authGSSServerInit;
  546. // Schedule the worker with lib_uv
  547. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  548. // Return no value as it's callback based
  549. info.GetReturnValue().Set(Nan::Undefined());
  550. }
  551. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  552. // authGSSServerClean
  553. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  554. static void _authGSSServerClean(Worker *worker) {
  555. gss_client_response *response;
  556. // Unpack the parameter data struct
  557. AuthGSSServerCleanCall *call = (AuthGSSServerCleanCall *)worker->parameters;
  558. // Perform authentication step
  559. response = authenticate_gss_server_clean(call->context->server_state);
  560. // If we have an error mark worker as having had an error
  561. if(response->return_code == AUTH_GSS_ERROR) {
  562. worker->error = TRUE;
  563. worker->error_code = response->return_code;
  564. worker->error_message = response->message;
  565. } else {
  566. worker->return_code = response->return_code;
  567. }
  568. // Free up structure
  569. free(call);
  570. free(response);
  571. }
  572. static Local<Value> _map_authGSSServerClean(Worker *worker) {
  573. Nan::HandleScope scope;
  574. // Return the return code
  575. return Nan::New<Int32>(worker->return_code);
  576. }
  577. // Initialize method
  578. NAN_METHOD(Kerberos::AuthGSSServerClean) {
  579. // // Ensure valid call
  580. if(info.Length() != 2) return Nan::ThrowError("Requires a GSS context and callback function");
  581. if(!KerberosContext::HasInstance(info[0]) || !info[1]->IsFunction()) return Nan::ThrowError("Requires a GSS context and callback function");
  582. // Let's unpack the kerberos context
  583. Local<Object> object = info[0]->ToObject();
  584. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  585. if (!kerberos_context->IsServerInstance()) {
  586. return Nan::ThrowError("GSS context is not a server instance");
  587. }
  588. // Allocate a structure
  589. AuthGSSServerCleanCall *call = (AuthGSSServerCleanCall *)calloc(1, sizeof(AuthGSSServerCleanCall));
  590. if(call == NULL) die("Memory allocation failed");
  591. call->context = kerberos_context;
  592. // Unpack the callback
  593. Local<Function> callbackHandle = Local<Function>::Cast(info[1]);
  594. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  595. // Let's allocate some space
  596. Worker *worker = new Worker();
  597. worker->error = false;
  598. worker->request.data = worker;
  599. worker->callback = callback;
  600. worker->parameters = call;
  601. worker->execute = _authGSSServerClean;
  602. worker->mapper = _map_authGSSServerClean;
  603. // Schedule the worker with lib_uv
  604. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  605. // Return no value as it's callback based
  606. info.GetReturnValue().Set(Nan::Undefined());
  607. }
  608. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  609. // authGSSServerStep
  610. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  611. static void _authGSSServerStep(Worker *worker) {
  612. gss_server_state *state;
  613. gss_client_response *response;
  614. char *auth_data;
  615. // Unpack the parameter data struct
  616. AuthGSSServerStepCall *call = (AuthGSSServerStepCall *)worker->parameters;
  617. // Get the state
  618. state = call->context->server_state;
  619. auth_data = call->auth_data;
  620. // Check if we got auth_data or not
  621. if(call->auth_data == NULL) {
  622. auth_data = (char *)"";
  623. }
  624. // Perform authentication step
  625. response = authenticate_gss_server_step(state, auth_data);
  626. // If we have an error mark worker as having had an error
  627. if(response->return_code == AUTH_GSS_ERROR) {
  628. worker->error = TRUE;
  629. worker->error_code = response->return_code;
  630. worker->error_message = response->message;
  631. } else {
  632. worker->return_code = response->return_code;
  633. }
  634. // Free up structure
  635. if(call->auth_data != NULL) free(call->auth_data);
  636. free(call);
  637. free(response);
  638. }
  639. static Local<Value> _map_authGSSServerStep(Worker *worker) {
  640. Nan::HandleScope scope;
  641. // Return the return code
  642. return Nan::New<Int32>(worker->return_code);
  643. }
  644. // Initialize method
  645. NAN_METHOD(Kerberos::AuthGSSServerStep) {
  646. // Ensure valid call
  647. if(info.Length() != 3) return Nan::ThrowError("Requires a GSS context, auth-data string and callback function");
  648. if(!KerberosContext::HasInstance(info[0])) return Nan::ThrowError("1st arg must be a GSS context");
  649. if (!info[1]->IsString()) return Nan::ThrowError("2nd arg must be auth-data string");
  650. if (!info[2]->IsFunction()) return Nan::ThrowError("3rd arg must be a callback function");
  651. // Auth-data string
  652. char *auth_data_str = NULL;
  653. // Let's unpack the parameters
  654. Local<Object> object = info[0]->ToObject();
  655. KerberosContext *kerberos_context = KerberosContext::Unwrap<KerberosContext>(object);
  656. if (!kerberos_context->IsServerInstance()) {
  657. return Nan::ThrowError("GSS context is not a server instance");
  658. }
  659. // Unpack the auth_data string
  660. Local<String> auth_data = info[1]->ToString();
  661. // Convert uri string to c-string
  662. auth_data_str = (char *)calloc(auth_data->Utf8Length() + 1, sizeof(char));
  663. if(auth_data_str == NULL) die("Memory allocation failed");
  664. // Write v8 string to c-string
  665. auth_data->WriteUtf8(auth_data_str);
  666. // Allocate a structure
  667. AuthGSSServerStepCall *call = (AuthGSSServerStepCall *)calloc(1, sizeof(AuthGSSServerStepCall));
  668. if(call == NULL) die("Memory allocation failed");
  669. call->context = kerberos_context;
  670. call->auth_data = auth_data_str;
  671. // Unpack the callback
  672. Local<Function> callbackHandle = Local<Function>::Cast(info[2]);
  673. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  674. // Let's allocate some space
  675. Worker *worker = new Worker();
  676. worker->error = false;
  677. worker->request.data = worker;
  678. worker->callback = callback;
  679. worker->parameters = call;
  680. worker->execute = _authGSSServerStep;
  681. worker->mapper = _map_authGSSServerStep;
  682. // Schedule the worker with lib_uv
  683. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  684. // Return no value as it's callback based
  685. info.GetReturnValue().Set(Nan::Undefined());
  686. }
  687. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  688. // authUserKrb5Password
  689. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  690. static void _authUserKrb5Password(Worker *worker) {
  691. AuthUserKrb5PasswordCall *call = (AuthUserKrb5PasswordCall *)worker->parameters;
  692. gss_client_response *response = authenticate_user_krb5_password(call->username, call->password, call->service);
  693. free(call->username);
  694. free(call->password);
  695. free(call->service);
  696. free(call);
  697. // If we have an error mark worker as having had an error
  698. if(response->return_code == AUTH_GSS_ERROR) {
  699. worker->error = TRUE;
  700. worker->error_code = response->return_code;
  701. worker->error_message = response->message;
  702. } else {
  703. worker->return_code = response->return_code;
  704. }
  705. free(response);
  706. }
  707. static Local<Value> _map_authUserKrb5Password(Worker *worker) {
  708. return worker->return_code ? Nan::True() : Nan::False();
  709. }
  710. NAN_METHOD(Kerberos::AuthUserKrb5Password) {
  711. const char *usage = "Requires a username (string), password (string), service (string) and callback (function(err,boolean))";
  712. if(info.Length() != 4) return Nan::ThrowError(usage);
  713. if(!info[0]->IsString()) return Nan::ThrowError(usage);
  714. if(!info[1]->IsString()) return Nan::ThrowError(usage);
  715. if(!info[2]->IsString()) return Nan::ThrowError(usage);
  716. if(!info[3]->IsFunction()) return Nan::ThrowError(usage);
  717. AuthUserKrb5PasswordCall *call = (AuthUserKrb5PasswordCall *)calloc(1, sizeof(AuthUserKrb5PasswordCall));
  718. if (call == NULL) die("Memory allocation failed");
  719. // Unpack the strings
  720. Local<String> username_str = info[0]->ToString();
  721. Local<String> password_str = info[1]->ToString();
  722. Local<String> service_str = info[2]->ToString();
  723. call->username = (char *)calloc(username_str->Utf8Length() + 1, sizeof(char));
  724. call->password = (char *)calloc(password_str->Utf8Length() + 1, sizeof(char));
  725. call->service = (char *)calloc(service_str->Utf8Length() + 1, sizeof(char));
  726. if (call->username == NULL || call->password == NULL || call->service == NULL) {
  727. die("Memory allocation failed");
  728. }
  729. username_str->WriteUtf8(call->username);
  730. password_str->WriteUtf8(call->password);
  731. service_str->WriteUtf8(call->service);
  732. // Unpack the callback
  733. Local<Function> callbackHandle = Local<Function>::Cast(info[3]);
  734. Nan::Callback *callback = new Nan::Callback(callbackHandle);
  735. Worker *worker = new Worker();
  736. worker->error = false;
  737. worker->request.data = worker;
  738. worker->callback = callback;
  739. worker->parameters = call;
  740. worker->execute = _authUserKrb5Password;
  741. worker->mapper = _map_authUserKrb5Password;
  742. // Schedule the worker with lib_uv
  743. uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After);
  744. // Return no value as it's callback based
  745. info.GetReturnValue().Set(Nan::Undefined());
  746. }
  747. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  748. // UV Lib callbacks
  749. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  750. void Kerberos::Process(uv_work_t* work_req) {
  751. // Grab the worker
  752. Worker *worker = static_cast<Worker*>(work_req->data);
  753. // Execute the worker code
  754. worker->execute(worker);
  755. }
  756. void Kerberos::After(uv_work_t* work_req) {
  757. // Grab the scope of the call from Node
  758. Nan::HandleScope scope;
  759. // Get the worker reference
  760. Worker *worker = static_cast<Worker*>(work_req->data);
  761. // If we have an error
  762. if(worker->error) {
  763. Local<Value> err = v8::Exception::Error(Nan::New<String>(worker->error_message).ToLocalChecked());
  764. Local<Object> obj = err->ToObject();
  765. obj->Set(Nan::New<String>("code").ToLocalChecked(), Nan::New<Int32>(worker->error_code));
  766. Local<Value> info[2] = { err, Nan::Null() };
  767. // Execute the error
  768. Nan::TryCatch try_catch;
  769. // Call the callback
  770. worker->callback->Call(ARRAY_SIZE(info), info);
  771. // If we have an exception handle it as a fatalexception
  772. if (try_catch.HasCaught()) {
  773. Nan::FatalException(try_catch);
  774. }
  775. } else {
  776. // // Map the data
  777. Local<Value> result = worker->mapper(worker);
  778. // Set up the callback with a null first
  779. #if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
  780. (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
  781. Local<Value> info[2] = { Nan::Null(), result};
  782. #else
  783. Local<Value> info[2] = { Nan::Null(), Nan::New<v8::Value>(result)};
  784. #endif
  785. // Wrap the callback function call in a TryCatch so that we can call
  786. // node's FatalException afterwards. This makes it possible to catch
  787. // the exception from JavaScript land using the
  788. // process.on('uncaughtException') event.
  789. Nan::TryCatch try_catch;
  790. // Call the callback
  791. worker->callback->Call(ARRAY_SIZE(info), info);
  792. // If we have an exception handle it as a fatalexception
  793. if (try_catch.HasCaught()) {
  794. Nan::FatalException(try_catch);
  795. }
  796. }
  797. // Clean up the memory
  798. delete worker->callback;
  799. delete worker;
  800. }
  801. // Exporting function
  802. NAN_MODULE_INIT(init) {
  803. Kerberos::Initialize(target);
  804. KerberosContext::Initialize(target);
  805. }
  806. NODE_MODULE(kerberos, init);