1 /**
2  *     Copyright 2016-2017 Couchbase, Inc.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16 
17 #include "couchbase.h"
18 
19 #include <ext/standard/md5.h>
20 
21 #define LOGARGS(lvl) LCB_LOG_##lvl, NULL, "pcbc/password_authenticator", __FILE__, __LINE__
22 
23 zend_class_entry *pcbc_password_authenticator_ce;
24 extern zend_class_entry *pcbc_authenticator_ce;
25 
26 /* {{{ proto void PasswordAuthenticator::__construct() */
PHP_METHOD(PasswordAuthenticator,__construct)27 PHP_METHOD(PasswordAuthenticator, __construct)
28 {
29     pcbc_password_authenticator_t *obj;
30     int rv;
31 
32     rv = zend_parse_parameters_none();
33     if (rv == FAILURE) {
34         throw_pcbc_exception("Invalid arguments.", LCB_EINVAL);
35         RETURN_NULL();
36     }
37     obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
38     obj->username = NULL;
39     obj->username_len = 0;
40     obj->password = NULL;
41     obj->password_len = 0;
42 }
43 /* }}} */
44 
pcbc_password_authenticator_init(zval * return_value,char * username,int username_len,char * password,int password_len TSRMLS_DC)45 void pcbc_password_authenticator_init(zval *return_value, char *username, int username_len, char *password,
46                                       int password_len TSRMLS_DC)
47 {
48     pcbc_password_authenticator_t *obj;
49 
50     object_init_ex(return_value, pcbc_password_authenticator_ce);
51     obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(return_value);
52     obj->username = estrndup(username, username_len);
53     obj->username_len = username_len;
54     obj->password = estrndup(password, password_len);
55     obj->password_len = password_len;
56 }
57 
58 /* {{{ proto \Couchbase\PasswordAuthenticator PasswordAuthenticator::username(string $username)
59  */
PHP_METHOD(PasswordAuthenticator,username)60 PHP_METHOD(PasswordAuthenticator, username)
61 {
62     pcbc_password_authenticator_t *obj;
63     char *username = NULL;
64     pcbc_str_arg_size username_len;
65     int rv;
66 
67     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &username, &username_len);
68     if (rv == FAILURE) {
69         RETURN_NULL();
70     }
71 
72     obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
73 
74     if (obj->username) {
75         efree(obj->username);
76     }
77     obj->username_len = username_len;
78     obj->username = estrndup(username, username_len);
79 
80     RETURN_ZVAL(getThis(), 1, 0);
81 } /* }}} */
82 
83 /* {{{ proto \Couchbase\PasswordAuthenticator PasswordAuthenticator::password(string $password)
84  */
PHP_METHOD(PasswordAuthenticator,password)85 PHP_METHOD(PasswordAuthenticator, password)
86 {
87     pcbc_password_authenticator_t *obj;
88     char *password = NULL;
89     pcbc_str_arg_size password_len;
90     int rv;
91 
92     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &password, &password_len);
93     if (rv == FAILURE) {
94         RETURN_NULL();
95     }
96 
97     obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
98 
99     if (obj->password) {
100         efree(obj->password);
101     }
102     obj->password_len = password_len;
103     obj->password = estrndup(password, password_len);
104 
105     RETURN_ZVAL(getThis(), 1, 0);
106 } /* }}} */
107 
pcbc_generate_password_lcb_auth(pcbc_password_authenticator_t * auth,lcb_AUTHENTICATOR ** result,lcb_type_t type,const char * name,const char * password,char ** hash TSRMLS_DC)108 void pcbc_generate_password_lcb_auth(pcbc_password_authenticator_t *auth, lcb_AUTHENTICATOR **result, lcb_type_t type,
109                                      const char *name, const char *password, char **hash TSRMLS_DC)
110 {
111     PHP_MD5_CTX md5;
112     unsigned char digest[16];
113 
114     *result = lcbauth_new();
115     lcbauth_set_mode(*result, LCBAUTH_MODE_RBAC);
116     PHP_MD5Init(&md5);
117 
118     if (name && password) {
119         lcbauth_add_pass(*result, name, password, LCBAUTH_F_CLUSTER);
120         PHP_MD5Update(&md5, "rbac-extra", sizeof("rbac-extra"));
121         PHP_MD5Update(&md5, name, strlen(name));
122         PHP_MD5Update(&md5, password, strlen(password));
123     } else {
124         lcbauth_add_pass(*result, auth->username, auth->password, LCBAUTH_F_CLUSTER);
125         PHP_MD5Update(&md5, "rbac", sizeof("rbac"));
126         PHP_MD5Update(&md5, auth->username, auth->username_len);
127         PHP_MD5Update(&md5, auth->password, auth->password_len);
128     }
129     PHP_MD5Final(digest, &md5);
130     *hash = ecalloc(sizeof(char), 33);
131     make_digest(*hash, digest);
132 }
133 
134 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_none, 0, 0, 0)
135 ZEND_END_ARG_INFO()
136 
137 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_username, 0, 0, 1)
138 ZEND_ARG_INFO(0, username)
139 ZEND_END_ARG_INFO()
140 
141 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_password, 0, 0, 2)
142 ZEND_ARG_INFO(0, password)
143 ZEND_END_ARG_INFO()
144 
145 // clang-format off
146 zend_function_entry password_authenticator_methods[] = {
147     PHP_ME(PasswordAuthenticator, __construct, ai_PasswordAuthenticator_none, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
148     PHP_ME(PasswordAuthenticator, username, ai_PasswordAuthenticator_username, ZEND_ACC_PUBLIC)
149     PHP_ME(PasswordAuthenticator, password, ai_PasswordAuthenticator_password, ZEND_ACC_PUBLIC)
150     PHP_FE_END
151 };
152 // clang-format on
153 
154 zend_object_handlers password_authenticator_handlers;
155 
password_authenticator_free_object(pcbc_free_object_arg * object TSRMLS_DC)156 static void password_authenticator_free_object(pcbc_free_object_arg *object TSRMLS_DC) /* {{{ */
157 {
158     pcbc_password_authenticator_t *obj = Z_PASSWORD_AUTHENTICATOR_OBJ(object);
159 
160     if (obj->username != NULL) {
161         efree(obj->username);
162     }
163     if (obj->password != NULL) {
164         efree(obj->password);
165     }
166 
167     zend_object_std_dtor(&obj->std TSRMLS_CC);
168 #if PHP_VERSION_ID < 70000
169     efree(obj);
170 #endif
171 } /* }}} */
172 
authenticator_create_object(zend_class_entry * class_type TSRMLS_DC)173 static pcbc_create_object_retval authenticator_create_object(zend_class_entry *class_type TSRMLS_DC)
174 {
175     pcbc_password_authenticator_t *obj = NULL;
176 
177     obj = PCBC_ALLOC_OBJECT_T(pcbc_password_authenticator_t, class_type);
178 
179     zend_object_std_init(&obj->std, class_type TSRMLS_CC);
180     object_properties_init(&obj->std, class_type);
181 
182 #if PHP_VERSION_ID >= 70000
183     obj->std.handlers = &password_authenticator_handlers;
184     return &obj->std;
185 #else
186     {
187         zend_object_value ret;
188         ret.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object,
189                                             password_authenticator_free_object, NULL TSRMLS_CC);
190         ret.handlers = &password_authenticator_handlers;
191         return ret;
192     }
193 #endif
194 }
195 
pcbc_password_authenticator_get_debug_info(zval * object,int * is_temp TSRMLS_DC)196 static HashTable *pcbc_password_authenticator_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
197 {
198     pcbc_password_authenticator_t *obj = NULL;
199 #if PHP_VERSION_ID >= 70000
200     zval retval;
201 #else
202     zval retval = zval_used_for_init;
203 #endif
204 
205     *is_temp = 1;
206     obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(object);
207 
208     array_init(&retval);
209     if (obj->username) {
210         ADD_ASSOC_STRING(&retval, "username", obj->username);
211     }
212     return Z_ARRVAL(retval);
213 } /* }}} */
214 
PHP_MINIT_FUNCTION(PasswordAuthenticator)215 PHP_MINIT_FUNCTION(PasswordAuthenticator)
216 {
217     zend_class_entry ce;
218 
219     INIT_NS_CLASS_ENTRY(ce, "Couchbase", "PasswordAuthenticator", password_authenticator_methods);
220     pcbc_password_authenticator_ce = zend_register_internal_class(&ce TSRMLS_CC);
221     pcbc_password_authenticator_ce->create_object = authenticator_create_object;
222     PCBC_CE_DISABLE_SERIALIZATION(pcbc_password_authenticator_ce);
223 
224     zend_class_implements(pcbc_password_authenticator_ce TSRMLS_CC, 1, pcbc_authenticator_ce);
225 
226     memcpy(&password_authenticator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
227     password_authenticator_handlers.get_debug_info = pcbc_password_authenticator_get_debug_info;
228 #if PHP_VERSION_ID >= 70000
229     password_authenticator_handlers.free_obj = password_authenticator_free_object;
230     password_authenticator_handlers.offset = XtOffsetOf(pcbc_password_authenticator_t, std);
231 #endif
232 
233     zend_register_class_alias("\\CouchbaseAuthenticator", pcbc_password_authenticator_ce);
234     return SUCCESS;
235 }
236