aclparse.cpp 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * Description (aclparse.c)
  8. *
  9. * This module provides functions for parsing a file containing
  10. * Access Control List (ACL) definitions. It builds a representation
  11. * of the ACLs in memory, using the services of the aclbuild module.
  12. */
  13. #include <base/systems.h>
  14. #include <base/file.h>
  15. #include <base/util.h>
  16. #include <netsite.h>
  17. #include <libaccess/nsadb.h>
  18. #include <libaccess/aclerror.h>
  19. #include <libaccess/aclparse.h>
  20. #include <libaccess/symbols.h>
  21. #ifdef XP_UNIX
  22. #include <sys/types.h>
  23. #include <netinet/in.h> /* ntohl */
  24. #include <arpa/inet.h>
  25. #endif
  26. void * aclChTab = 0; /* character class table handle */
  27. static char * classv[] = {
  28. " \t\r\f\013", /* class 0 - whitespace */
  29. "\n", /* class 1 - newline */
  30. ",.;@*()+{}\"\'", /* class 2 - special characters */
  31. "0123456789", /* class 3 - digits */
  32. /* class 4 - letters */
  33. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  34. "-", /* class 5 - hyphen */
  35. "_", /* class 6 - underscore */
  36. "/-_.:" /* class 7 - filename special characters */
  37. };
  38. static int classc = sizeof(classv)/sizeof(char *);
  39. /*
  40. * Description (aclAuthListParse)
  41. *
  42. * This function parses an auth-list. An auth-list specifies
  43. * combinations of user/group names and host addresses/names.
  44. * An auth-list entry can identify a collection of users and/or
  45. * groups, a collection of hosts by IP addresses or DNS names,
  46. * or a combination of the two. Each auth-spec adds another
  47. * ACClients_t structure to the specified list.
  48. *
  49. * The syntax for an auth-list is:
  50. *
  51. * auth-list ::= auth-spec | auth-list "," auth-spec
  52. * auth-spec ::= auth-users [at-token auth-hosts]
  53. * auth-users - see aclAuthUsersParse()
  54. * auth-hosts - see aclAuthHostsParse()
  55. * at-token ::= "at" | "@"
  56. *
  57. * The caller provides a pointer to a ClientSpec_t structure,
  58. * which is built up with new information as auth-specs are parsed.
  59. *
  60. * Arguments:
  61. *
  62. * errp - error frame list pointer (may be null)
  63. * acf - pointer to ACLFile_t for ACL file
  64. * acc - pointer to ACL context object
  65. * rlm - pointer to authentication realm object
  66. * clsp - pointer to returned ACClients_t list head
  67. *
  68. * Returns:
  69. *
  70. * If successful, the return value is the token type of the token
  71. * following the auth-list, i.e. the first token which is not
  72. * recognized as the start of an auth-spec. It is the caller's
  73. * responsibility to validate this token as a legitimate terminator
  74. * of an auth-list. If a parsing error occurs in the middle of
  75. * an auth-spec, the return value is ACLERRPARSE, and an error frame
  76. * is generated if an error list is provided. For other kinds of
  77. * errors a negative error code (from aclerror.h) is returned.
  78. */
  79. int aclAuthListParse(NSErr_t * errp, ACLFile_t * acf,
  80. ACContext_t * acc, Realm_t * rlm, ACClients_t **clsp)
  81. {
  82. void * token = acf->acf_token; /* token handle */
  83. ACClients_t * csp; /* client spec pointer */
  84. UserSpec_t * usp; /* user spec pointer */
  85. HostSpec_t * hsp; /* host spec pointer */
  86. int rv; /* result value */
  87. int eid; /* error id */
  88. /* Loop once for each auth-spec */
  89. for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
  90. usp = 0;
  91. hsp = 0;
  92. /* Parse auth-users into user and group lists in the ACClients_t */
  93. rv = aclAuthUsersParse(errp, acf, rlm, &usp, 0);
  94. if (rv < 0) break;
  95. /* Is the at-token there? */
  96. if ((rv == TOKEN_AT) || !strcasecmp(lex_token(token), KEYWORD_AT)) {
  97. /* Step to the next token after the at-token */
  98. rv = aclGetToken(errp, acf, 0);
  99. if (rv < 0) break;
  100. /* Parse auth-hosts part, adding information to the HostSpec_t */
  101. rv = aclAuthHostsParse(errp, acf, acc, &hsp);
  102. if (rv < 0) break;
  103. }
  104. /* Create a new ACClients_t structure for the parsed information */
  105. csp = (ACClients_t *)MALLOC(sizeof(ACClients_t));
  106. if (csp == 0) goto err_nomem;
  107. csp->cl_next = 0;
  108. csp->cl_user = usp;
  109. csp->cl_host = hsp;
  110. /* Add it to the end of the list referenced by clsp */
  111. while (*clsp != 0) clsp = &(*clsp)->cl_next;
  112. *clsp = csp;
  113. /* Need a "," to keep going */
  114. if (rv != TOKEN_COMMA) break;
  115. }
  116. return rv;
  117. err_nomem:
  118. eid = ACLERR1000;
  119. nserrGenerate(errp, ACLERRNOMEM, eid, ACL_Program, 0);
  120. return ACLERRNOMEM;
  121. }
  122. /*
  123. * Description (aclAuthHostsParse)
  124. *
  125. * This function parses a list of IP address and/or DNS name
  126. * specifications, adding information to the IP and DNS filters
  127. * associated with a specified HostSpec_t. The syntax of the
  128. * auth-hosts construct is:
  129. *
  130. * auth-hosts ::= auth-host-elem | "(" auth-host-list ")"
  131. * | "hosts" host-list-name
  132. * auth-host-elem ::= auth-ip-spec | auth-dns-spec
  133. * auth-ip-spec ::= ipaddr | ipaddr netmask
  134. * auth-dns-spec ::= fqdn | dns-suffix
  135. * auth-host-list ::= auth-host-elem | auth-host-list "," auth-host-elem
  136. *
  137. * Arguments:
  138. *
  139. * errp - error frame list pointer (may be null)
  140. * acf - pointer to ACLFile_t for ACL file
  141. * acc - pointer to ACL context object
  142. * hspp - pointer to HostSpec_t pointer
  143. *
  144. * Returns:
  145. *
  146. * If successful, the return value is the token type of the token
  147. * following the auth-hosts, i.e. either the first token after a
  148. * single auth-host-elem or the first token after the closing ")"
  149. * of a list of auth-host-elems. It is the caller's responsibility
  150. * to validate this token as a legitimate successor of auth-hosts.
  151. * If a parsing error occurs in the middle of auth-hosts, the return
  152. * value is ACLERRPARSE, and an error frame is generated if an error
  153. * list is provided. For other kinds of errors a negative error
  154. * code (from aclerror.h) is returned.
  155. */
  156. int aclAuthHostsParse(NSErr_t * errp,
  157. ACLFile_t * acf, ACContext_t * acc, HostSpec_t **hspp)
  158. {
  159. void * token = acf->acf_token; /* token handle */
  160. char * tokenstr; /* token string pointer */
  161. int islist = 0; /* true if auth-host-list */
  162. int fqdn; /* fully qualified domain name */
  163. IPAddr_t ipaddr; /* IP address value */
  164. IPAddr_t netmask; /* IP netmask value */
  165. int arv; /* alternate result value */
  166. int rv; /* result value */
  167. int eid; /* error id */
  168. char linestr[16]; /* line number string buffer */
  169. rv = acf->acf_ttype;
  170. /* Are we starting an auth-host-list? */
  171. if (rv == TOKEN_LPAREN) {
  172. /* Yes, it appears so */
  173. islist = 1;
  174. /* Step token to first auth-host-elem */
  175. rv = aclGetToken(errp, acf, 0);
  176. if (rv < 0) goto punt;
  177. }
  178. else if (rv == TOKEN_IDENT) {
  179. /* Could this be "hosts host-list-name"? */
  180. tokenstr = lex_token(token);
  181. if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
  182. /* We don't support lists of host lists yet */
  183. if (*hspp != 0) goto err_unshl;
  184. /* Get host-list-name */
  185. rv = aclGetToken(errp, acf, 0);
  186. if (rv < 0) goto punt;
  187. if (rv != TOKEN_IDENT) goto err_hlname;
  188. tokenstr = lex_token(token);
  189. /* Look up the host-list-name in the ACL symbol table */
  190. rv = symTableFindSym(acc->acc_stp,
  191. tokenstr, ACLSYMHOST, (void **)hspp);
  192. if (rv < 0) goto err_undefhl;
  193. /* Step to token after the host-list-name */
  194. rv = aclGetToken(errp, acf, 0);
  195. return rv;
  196. }
  197. }
  198. /* Loop for each auth-host-elem */
  199. for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
  200. /* Does this look like an auth-ip-spec? */
  201. if (rv == TOKEN_NUMBER) {
  202. /* Yes, go parse it */
  203. rv = aclGetIPAddr(errp, acf, &ipaddr, &netmask);
  204. if (rv < 0) goto punt;
  205. arv = aclAuthIPAdd(hspp, ipaddr, netmask);
  206. if (arv < 0) goto err_ipadd;
  207. }
  208. else if ((rv == TOKEN_STAR) || (rv == TOKEN_IDENT)) {
  209. /* Get fully qualified DNS name indicator value */
  210. fqdn = (rv == TOKEN_IDENT) ? 1 : 0;
  211. /* This looks like the start of an auth-dns-spec */
  212. rv = aclGetDNSString(errp, acf);
  213. if (rv < 0) goto punt;
  214. tokenstr = lex_token(token);
  215. /* If the DNS spec begins with "*.", strip the "*" */
  216. if (tokenstr && (tokenstr[0] == '*') && (tokenstr[1] == '.')) {
  217. tokenstr += 1;
  218. }
  219. arv = aclAuthDNSAdd(hspp, tokenstr, fqdn);
  220. if (arv < 0) goto err_dnsadd;
  221. /* Pick up the next token */
  222. rv = aclGetToken(errp, acf, 0);
  223. }
  224. else break;
  225. /* If this is a list, we need a "," to keep going */
  226. if (!islist || (rv != TOKEN_COMMA)) break;
  227. }
  228. /* Were we parsing an auth-host-list? */
  229. if (islist) {
  230. /* Yes, check for closing ")" */
  231. if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
  232. /* Got it. Step to next token for caller. */
  233. rv = aclGetToken(errp, acf, 0);
  234. }
  235. punt:
  236. return rv;
  237. err_unshl:
  238. eid = ACLERR1100;
  239. goto err_parse;
  240. err_hlname:
  241. eid = ACLERR1120;
  242. goto err_parse;
  243. err_undefhl:
  244. eid = ACLERR1140;
  245. rv = ACLERRUNDEF;
  246. sprintf(linestr, "%d", acf->acf_lineno);
  247. nserrGenerate(errp, rv, eid, ACL_Program,
  248. 3, acf->acf_filename, linestr, tokenstr);
  249. goto punt;
  250. err_ipadd:
  251. eid = ACLERR1180;
  252. rv = arv;
  253. goto err_ret;
  254. err_dnsadd:
  255. eid = ACLERR1200;
  256. rv = arv;
  257. goto err_ret;
  258. err_ret:
  259. nserrGenerate(errp, rv, eid, ACL_Program, 0);
  260. goto punt;
  261. err_norp:
  262. eid = ACLERR1220;
  263. err_parse:
  264. rv = ACLERRPARSE;
  265. sprintf(linestr, "%d", acf->acf_lineno);
  266. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  267. goto punt;
  268. }
  269. /*
  270. * Description (aclAuthUsersParse)
  271. *
  272. * This function parses a list of users and groups subject to
  273. * authorization, adding the information to a specified UserSpec_t.
  274. * The syntax it parses is:
  275. *
  276. * auth-users ::= auth-user-elem | "(" auth-user-list ")"
  277. * auth-user-elem ::= username | groupname
  278. * | "all" | "anyone"
  279. * auth-user-list ::= auth-user-elem | auth-user-list "," auth-user-elem
  280. *
  281. * If the 'elist' argument is non-null, an auth-user-list will be
  282. * accepted without the enclosing parentheses. Any invalid user
  283. * or group names will not cause a fatal error, but will be returned
  284. * in an array of strings via 'elist'.
  285. *
  286. * Arguments:
  287. *
  288. * errp - error frame list pointer (may be null)
  289. * acf - pointer to ACLFile_t for ACL file
  290. * rlm - pointer to authentication realm object
  291. * uspp - pointer to UserSpec_t pointer
  292. * elist - pointer to returned pointer to array
  293. * of strings containing invalid user or
  294. * group names (may be null)
  295. *
  296. * Returns:
  297. *
  298. * If successful, the return value is the token type of the token
  299. * following the auth-users, i.e. either the first token after a
  300. * single auth-user-elem or the first token after the closing ")"
  301. * of a list of auth-user-elems. It is the caller's responsibility
  302. * to validate this token as a legitimate successor of auth-users.
  303. * If a parsing error occurs in the middle of auth-users, the return
  304. * value is ACLERRPARSE, and an error frame is generated if an error
  305. * list is provided. For other kinds of errors a negative error
  306. * code (from aclerror.h) is returned.
  307. */
  308. int aclAuthUsersParse(NSErr_t * errp, ACLFile_t * acf,
  309. Realm_t * rlm, UserSpec_t **uspp, char ***elist)
  310. {
  311. void * token = acf->acf_token; /* token handle */
  312. char * tokenstr; /* token string pointer */
  313. UserSpec_t * usp; /* user list head structure */
  314. int islist = 0; /* true if auth-user-list */
  315. int inlist = 0; /* true if UserSpec_t was supplied */
  316. int any = 0; /* true if KEYWORD_ANY seen */
  317. int all = 0; /* true if KEYWORD_ALL seen */
  318. int elemcnt = 0; /* count of auth-user-elem seen */
  319. int elen = 0; /* length of evec in (char *) */
  320. int ecnt = 0; /* entries used in evec */
  321. char **evec = 0; /* list of bad user/group names */
  322. int rv; /* result value */
  323. int eid; /* error id */
  324. char linestr[16]; /* line number string buffer */
  325. int errc = 2;
  326. usp = *uspp;
  327. if ((usp != 0) && (usp->us_flags & ACL_USALL)) all = 1;
  328. if (elist != 0) inlist = 1;
  329. else {
  330. /* Check for opening "(" */
  331. if (acf->acf_ttype == TOKEN_LPAREN) {
  332. /* Looks like an auth-user-list */
  333. islist = 1;
  334. /* Step token to first auth-user-elem */
  335. rv = aclGetToken(errp, acf, 0);
  336. if (rv < 0) goto punt;
  337. }
  338. }
  339. /* Loop for each auth-user-elem */
  340. for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
  341. /* Looking for a user or group identifier */
  342. if ((rv == TOKEN_IDENT) || (rv == TOKEN_STRING)) {
  343. /*
  344. * If KEYWORD_ALL or KEYWORD_ANY has already appeared
  345. * in this auth-spec, then return an error.
  346. */
  347. if (all | any) goto err_allany;
  348. /* Check for reserved words */
  349. tokenstr = lex_token(token);
  350. /* KEYWORD_AT begins auth-hosts, but is invalid here */
  351. if (!strcasecmp(tokenstr, KEYWORD_AT)) break;
  352. /* Check for special group names */
  353. if (!strcasecmp(tokenstr, KEYWORD_ANY)) {
  354. /*
  355. * Any user, with no authentication needed. This can
  356. * only appear once in an auth-spec, and cannot be used
  357. * in combination with KEYWORD_ALL (or any other user or
  358. * group identifiers, but that will get checked before
  359. * we return).
  360. */
  361. if ((elemcnt > 0) || (usp != 0)) goto err_any;
  362. any = 1;
  363. }
  364. else if (!strcasecmp(tokenstr, KEYWORD_ALL)) {
  365. /*
  366. * Any authenticated user. This can only appear once in
  367. * an auth-spec, and cannot be used in combination with
  368. * KEYWORD_ANY (or any other user or group identifiers,
  369. * but that will get checked before we return).
  370. */
  371. if (elemcnt > 0) goto err_all;
  372. /* Create a UserSpec_t structure if we haven't got one yet */
  373. if (usp == 0) {
  374. usp = aclUserSpecCreate();
  375. if (usp == 0) goto err_nomem1;
  376. *uspp = usp;
  377. }
  378. usp->us_flags |= ACL_USALL;
  379. all = 1;
  380. }
  381. else {
  382. /* Create a UserSpec_t structure if we haven't got one yet */
  383. if (usp == 0) {
  384. usp = aclUserSpecCreate();
  385. if (usp == 0) goto err_nomem2;
  386. *uspp = usp;
  387. }
  388. /* This should be a user or group name */
  389. rv = aclAuthNameAdd(errp, usp, rlm, tokenstr);
  390. if (rv <= 0) {
  391. /* The name was not found in the authentication DB */
  392. if (elist != 0) {
  393. if (evec == 0) {
  394. evec = (char **)MALLOC(4*sizeof(char *));
  395. evec[0] = 0;
  396. ecnt = 1;
  397. elen = 4;
  398. }
  399. else if (ecnt >= elen) {
  400. elen += 4;
  401. evec = (char **)REALLOC(evec, elen*sizeof(char *));
  402. }
  403. evec[ecnt-1] = STRDUP(tokenstr);
  404. evec[ecnt] = 0;
  405. ++ecnt;
  406. }
  407. else if (rv < 0) goto err_badgun;
  408. }
  409. /* Don't allow duplicate names */
  410. if (rv & ANA_DUP) {
  411. if (elist == 0) goto err_dupgun;
  412. }
  413. }
  414. /* Count number of auth-user-elems seen */
  415. elemcnt += 1;
  416. /* Get the token after the auth-user-elem */
  417. rv = aclGetToken(errp, acf, 0);
  418. if (rv < 0) goto punt;
  419. }
  420. /* If this is a list, we need a "," to keep going */
  421. if (!(islist | inlist) || (rv != TOKEN_COMMA)) break;
  422. }
  423. /* Were we parsing an auth-user-list? */
  424. if (islist) {
  425. /* Yes, check for closing ")" */
  426. if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
  427. /* Got it. Step to next token for caller. */
  428. rv = aclGetToken(errp, acf, 0);
  429. if (rv < 0) goto punt;
  430. }
  431. /*
  432. * If we didn't see any auth-user-elems, then the auth-user we were
  433. * called to parse is missing. We will forgive and forget if the
  434. * current token is a comma, however, so as to allow empty auth-specs.
  435. */
  436. if ((elemcnt <= 0) && (rv != TOKEN_COMMA)) {
  437. goto err_noelem;
  438. }
  439. punt:
  440. /* Return list of bad names if indicated */
  441. if (elist != 0) *elist = evec;
  442. return rv;
  443. err_badgun:
  444. /* Encountered an unknown user or group name */
  445. eid = ACLERR1360;
  446. rv = ACLERRUNDEF;
  447. goto err_retgun;
  448. err_dupgun:
  449. /* A user or group name was specified multiple times */
  450. eid = ACLERR1380;
  451. rv = ACLERRDUPSYM;
  452. goto err_retgun;
  453. err_retgun:
  454. sprintf(linestr, "%d", acf->acf_lineno);
  455. nserrGenerate(errp, rv, eid, ACL_Program,
  456. 3, acf->acf_filename, linestr, tokenstr);
  457. goto punt;
  458. err_norp:
  459. /* Missing ")" */
  460. eid = ACLERR1400;
  461. goto err_parse;
  462. err_noelem:
  463. eid = ACLERR1420;
  464. goto err_parse;
  465. err_all:
  466. eid = ACLERR1440;
  467. goto err_parse;
  468. err_any:
  469. eid = ACLERR1460;
  470. goto err_parse;
  471. err_allany:
  472. eid = ACLERR1480;
  473. goto err_parse;
  474. err_nomem1:
  475. eid = ACLERR1500;
  476. rv = ACLERRNOMEM;
  477. errc = 0;
  478. goto err_ret;
  479. err_nomem2:
  480. eid = ACLERR1520;
  481. rv = ACLERRNOMEM;
  482. errc = 0;
  483. goto err_ret;
  484. err_parse:
  485. rv = ACLERRPARSE;
  486. err_ret:
  487. sprintf(linestr, "%d", acf->acf_lineno);
  488. nserrGenerate(errp, rv, eid, ACL_Program, errc, acf->acf_filename, linestr);
  489. goto punt;
  490. }
  491. /*
  492. * Description (aclDirectivesParse)
  493. *
  494. * This function parses the directives inside an ACL definition.
  495. * The syntax for a directive list is:
  496. *
  497. * dir-list ::= directive | dir-list ";" directive
  498. * directive ::= auth-directive | access-directive | exec-directive
  499. * auth-directive ::= dir-force "authenticate" ["in" realm-spec]
  500. * access-directive ::= dir-force dir-access auth-list
  501. * exec-directive ::= dir-force "execute" ["if" exec-optlist]
  502. * exec-optlist ::= exec-condition | exec-optlist "," exec-condition
  503. * exec-condition ::= dir-access | "authenticate"
  504. * dir-force ::= "Always" | "Default"
  505. * dir-access ::= "allow" | "deny"
  506. *
  507. * See aclAuthListParse() for auth-list syntax.
  508. * See aclRealmSpecParse() for realm-spec syntax.
  509. *
  510. * The caller provides a pointer to an ACL structure, which is
  511. * built up with new information as directives are parsed.
  512. *
  513. * Arguments:
  514. *
  515. * errp - error frame list pointer (may be null)
  516. * acf - pointer to ACLFile_t for ACL file
  517. * acl - pointer to ACL structure
  518. *
  519. * Returns:
  520. *
  521. * If successful, the return value is the token type of the token
  522. * following the directive list, i.e. the first token which is not
  523. * recognized as the start of a directive. It is the caller's
  524. * responsibility to validate this token as a legitimate terminator
  525. * of a directive list. If a parsing error occurs in the middle of
  526. * a directive, the return value is ACLERRPARSE, and an error frame
  527. * is generated if an error list is provided. For other kinds of
  528. * errors a negative error code (from aclerror.h) is returned.
  529. */
  530. int aclDirectivesParse(NSErr_t * errp, ACLFile_t * acf, ACL_t * acl)
  531. {
  532. void * token = acf->acf_token; /* token handle */
  533. char * tokenstr; /* token string */
  534. Realm_t * rlm = 0; /* current realm pointer */
  535. ACDirective_t * acd; /* directive pointer */
  536. int action; /* directive action code */
  537. int flags; /* directive action flags */
  538. int arv; /* alternate return value */
  539. int rv; /* result value */
  540. int eid; /* error id */
  541. char linestr[16]; /* line number string buffer */
  542. /* Look for top-level directives */
  543. for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
  544. action = 0;
  545. flags = 0;
  546. /* Check for beginning of directive */
  547. if (rv == TOKEN_IDENT) {
  548. /* Check identifier for directive dir-force keywords */
  549. tokenstr = lex_token(token);
  550. if (!strcasecmp(tokenstr, KEYWORD_DEFAULT)) {
  551. flags = ACD_DEFAULT;
  552. }
  553. else if (!strcasecmp(tokenstr, "always")) {
  554. flags = ACD_ALWAYS;
  555. }
  556. else break;
  557. /*
  558. * Now we're looking for dir-access, "authenticate",
  559. * or "execute".
  560. */
  561. rv = aclGetToken(errp, acf, 0);
  562. /* An identifier would be nice ... */
  563. if (rv != TOKEN_IDENT) goto err_access;
  564. tokenstr = lex_token(token);
  565. if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
  566. /* process auth-directive */
  567. action = ACD_AUTH;
  568. /* Create a new directive object */
  569. acd = aclDirectiveCreate();
  570. if (acd == 0) goto err_nomem1;
  571. /* Get the next token after KEYWORD_AUTH */
  572. rv = aclGetToken(errp, acf, 0);
  573. if (rv < 0) break;
  574. /* Could we have "in" realm-spec here? */
  575. if (rv == TOKEN_IDENT) {
  576. tokenstr = lex_token(token);
  577. if (!strcasecmp(tokenstr, KEYWORD_IN)) {
  578. /* Get the next token after KEYWORD_IN */
  579. rv = aclGetToken(errp, acf, 0);
  580. if (rv < 0) break;
  581. /* Parse the realm-spec */
  582. rv = aclRealmSpecParse(errp, acf, acl->acl_acc,
  583. &acd->acd_auth.au_realm);
  584. if (rv < 0) break;
  585. /* Set current realm */
  586. if (acd->acd_auth.au_realm != 0) {
  587. /* Close database in current realm if any */
  588. if (rlm && rlm->rlm_authdb) {
  589. (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
  590. rlm->rlm_authdb = 0;
  591. }
  592. rlm = &acd->acd_auth.au_realm->rs_realm;
  593. }
  594. }
  595. }
  596. /* Add this directive to the ACL */
  597. acd->acd_action = action;
  598. acd->acd_flags = flags;
  599. arv = aclDirectiveAdd(acl, acd);
  600. if (arv < 0) goto err_diradd1;
  601. }
  602. else if (!strcasecmp(tokenstr, KEYWORD_EXECUTE)) {
  603. /* process exec-directive */
  604. action = ACD_EXEC;
  605. /* Create a new directive object */
  606. acd = aclDirectiveCreate();
  607. if (acd == 0) goto err_nomem3;
  608. /* Get the next token after KEYWORD_EXECUTE */
  609. rv = aclGetToken(errp, acf, 0);
  610. if (rv < 0) break;
  611. /* Could we have "if" exec-optlist here? */
  612. if (rv == TOKEN_IDENT) {
  613. tokenstr = lex_token(token);
  614. if (!strcasecmp(tokenstr, KEYWORD_IF)) {
  615. for (;;) {
  616. /* Get the next token after KEYWORD_IF or "," */
  617. rv = aclGetToken(errp, acf, 0);
  618. if (rv < 0) break;
  619. /*
  620. * Looking for "allow", "deny", or "authenticate"
  621. */
  622. if (rv == TOKEN_IDENT) {
  623. tokenstr = lex_token(token);
  624. if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
  625. flags |= ACD_EXALLOW;
  626. }
  627. else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
  628. flags |= ACD_EXDENY;
  629. }
  630. else if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
  631. flags |= ACD_EXAUTH;
  632. }
  633. else goto err_exarg;
  634. }
  635. /* End of directive if no comma */
  636. rv = aclGetToken(errp, acf, 0);
  637. if (rv < 0) break;
  638. if (rv != TOKEN_COMMA) break;
  639. }
  640. }
  641. }
  642. else flags = (ACD_EXALLOW|ACD_EXDENY|ACD_EXAUTH);
  643. if (rv < 0) break;
  644. /* Add this directive to the ACL */
  645. acd->acd_action = action;
  646. acd->acd_flags = flags;
  647. arv = aclDirectiveAdd(acl, acd);
  648. if (arv < 0) goto err_diradd3;
  649. }
  650. else {
  651. /* process access-directive */
  652. if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
  653. action = ACD_ALLOW;
  654. }
  655. else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
  656. action = ACD_DENY;
  657. }
  658. else goto err_acctype;
  659. /* Get the next token after dir-access */
  660. rv = aclGetToken(errp, acf, 0);
  661. /* Create a new directive object */
  662. acd = aclDirectiveCreate();
  663. if (acd == 0) goto err_nomem2;
  664. /* Parse a list of auth-specs */
  665. rv = aclAuthListParse(errp, acf, acl->acl_acc, rlm,
  666. &acd->acd_cl);
  667. if (rv < 0) break;
  668. /* Add this directive to the ACL */
  669. acd->acd_action = action;
  670. acd->acd_flags = flags;
  671. arv = aclDirectiveAdd(acl, acd);
  672. if (arv < 0) goto err_diradd2;
  673. }
  674. }
  675. /* Need a ";" to keep going */
  676. if (rv != TOKEN_EOS) break;
  677. }
  678. punt:
  679. /* Close database in current realm if any */
  680. if (rlm && rlm->rlm_authdb) {
  681. (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
  682. rlm->rlm_authdb = 0;
  683. }
  684. return rv;
  685. err_access:
  686. /* dir-access not present */
  687. eid = ACLERR1600;
  688. rv = ACLERRPARSE;
  689. goto err_ret;
  690. err_acctype:
  691. /* dir-access identifier is invalid */
  692. eid = ACLERR1620;
  693. rv = ACLERRPARSE;
  694. goto err_ret;
  695. err_diradd1:
  696. eid = ACLERR1640;
  697. rv = arv;
  698. tokenstr = 0;
  699. goto err_ret;
  700. err_diradd2:
  701. eid = ACLERR1650;
  702. rv = arv;
  703. tokenstr = 0;
  704. goto err_ret;
  705. err_nomem1:
  706. eid = ACLERR1660;
  707. rv = ACLERRNOMEM;
  708. tokenstr = 0;
  709. goto err_ret;
  710. err_nomem2:
  711. eid = ACLERR1680;
  712. rv = ACLERRNOMEM;
  713. tokenstr = 0;
  714. goto err_ret;
  715. err_nomem3:
  716. eid = ACLERR1685;
  717. rv = ACLERRNOMEM;
  718. tokenstr = 0;
  719. goto err_ret;
  720. err_diradd3:
  721. eid = ACLERR1690;
  722. rv = arv;
  723. tokenstr = 0;
  724. goto err_ret;
  725. err_exarg:
  726. eid = ACLERR1695;
  727. rv = ACLERRSYNTAX;
  728. goto err_ret;
  729. err_ret:
  730. sprintf(linestr, "%d", acf->acf_lineno);
  731. if (tokenstr) {
  732. nserrGenerate(errp, rv, eid, ACL_Program,
  733. 3, acf->acf_filename, linestr, tokenstr);
  734. }
  735. else {
  736. nserrGenerate(errp, rv, eid, ACL_Program,
  737. 2, acf->acf_filename, linestr);
  738. }
  739. goto punt;
  740. }
  741. /*
  742. * Description (aclACLParse)
  743. *
  744. * This function parses a data stream containing ACL definitions,
  745. * and builds a representation of the ACLs in memory. Each ACL
  746. * has a user-specified name, and a pointer to the ACL structure
  747. * is stored under the name in a symbol table provided by the caller.
  748. *
  749. * Arguments:
  750. *
  751. * errp - error frame list pointer (may be null)
  752. * acf - pointer to ACLFile_t for ACL file
  753. * acc - pointer to ACContext_t structure
  754. * flags - bit flags (unused - must be zero)
  755. *
  756. * Returns:
  757. *
  758. * The return value is zero if the stream is parsed successfully.
  759. * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
  760. * and an error frame will be generated if an error list is provided.
  761. */
  762. int aclACLParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc, int flags)
  763. {
  764. void * token = acf->acf_token; /* handle for current token */
  765. char * tokenstr; /* current token string */
  766. char * aclname; /* ACL name string */
  767. ACL_t * aclp; /* pointer to ACL structure */
  768. int rv; /* result value */
  769. int eid; /* error id value */
  770. char linestr[16]; /* line number string buffer */
  771. /* Look for top-level statements */
  772. for (;;) {
  773. /* Get a token to begin a statement */
  774. rv = aclGetToken(errp, acf, 0);
  775. /* An identifier would be nice ... */
  776. if (rv != TOKEN_IDENT) {
  777. /* Empty statements are ok, if pointless */
  778. if (rv == TOKEN_EOS) continue;
  779. /* EOF is valid here */
  780. if (rv == TOKEN_EOF) break;
  781. /* Anything else is unacceptable */
  782. goto err_nostmt;
  783. }
  784. /* Check identifier for statement keywords */
  785. tokenstr = lex_token(token);
  786. if (!strcasecmp(tokenstr, KEYWORD_ACL)) {
  787. /* ACL name rights-list { acl-def-list }; */
  788. /* Get the name of the ACL */
  789. rv = aclGetToken(errp, acf, 0);
  790. if (rv != TOKEN_IDENT) goto err_aclname;
  791. aclname = lex_token(token);
  792. /* Create the ACL structure */
  793. rv = aclCreate(errp, acc, aclname, &aclp);
  794. if (rv < 0) goto punt;
  795. /* Get the next token after the ACL name */
  796. rv = aclGetToken(errp, acf, 0);
  797. /* Parse the rights specification */
  798. rv = aclRightsParse(errp, acf, acc, &aclp->acl_rights);
  799. /* Want a "{" to open the ACL directive list */
  800. if (rv != TOKEN_LBRACE) {
  801. if (rv < 0) goto punt;
  802. goto err_aclopen;
  803. }
  804. /* Get the first token in the ACL directive list */
  805. rv = aclGetToken(errp, acf, 0);
  806. if (rv < 0) goto punt;
  807. /* Parse the ACL directive list */
  808. rv = aclDirectivesParse(errp, acf, aclp);
  809. /* Want a "}" to close the ACL directive list */
  810. if (rv != TOKEN_RBRACE) {
  811. if (rv < 0) goto punt;
  812. goto err_aclclose;
  813. }
  814. }
  815. else if (!strcasecmp(tokenstr, KEYWORD_INCLUDE)) {
  816. /* Include "filename"; */
  817. }
  818. else if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
  819. /* Realm name realm-spec */
  820. }
  821. else if (!strcasecmp(tokenstr, KEYWORD_RIGHTS)) {
  822. /* Rights name rights-def; */
  823. }
  824. else if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
  825. /* Hosts name auth-hosts; */
  826. }
  827. else goto err_syntax;
  828. }
  829. return 0;
  830. err_nostmt:
  831. eid = ACLERR1700;
  832. rv = ACLERRPARSE;
  833. goto err_ret;
  834. err_aclname:
  835. eid = ACLERR1720;
  836. rv = ACLERRPARSE;
  837. goto err_ret;
  838. err_aclopen:
  839. eid = ACLERR1740;
  840. rv = ACLERRPARSE;
  841. goto err_ret;
  842. err_aclclose:
  843. eid = ACLERR1760;
  844. rv = ACLERRPARSE;
  845. goto err_ret;
  846. err_ret:
  847. sprintf(linestr, "%d", acf->acf_lineno);
  848. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  849. goto punt;
  850. err_syntax:
  851. eid = ACLERR1780;
  852. rv = ACLERRPARSE;
  853. sprintf(linestr, "%d", acf->acf_lineno);
  854. nserrGenerate(errp, rv, eid, ACL_Program,
  855. 3, acf->acf_filename, linestr, tokenstr);
  856. punt:
  857. return rv;
  858. }
  859. /*
  860. * Description (aclFileClose)
  861. *
  862. * This function closes an ACL file previously opened by aclFileOpen(),
  863. * and frees any associated data structures.
  864. *
  865. * Arguments:
  866. *
  867. * acf - pointer to ACL file information
  868. * flags - bit flags (unused - must be zero)
  869. */
  870. void aclFileClose(ACLFile_t * acf, int flags)
  871. {
  872. if (acf != 0) {
  873. /* Destroy the associated lexer stream if any */
  874. if (acf->acf_lst != 0) {
  875. lex_stream_destroy(acf->acf_lst);
  876. }
  877. /* Close the file if it's open */
  878. if (acf->acf_fd != SYS_ERROR_FD) {
  879. system_fclose(acf->acf_fd);
  880. }
  881. /* Destroy any associated token */
  882. if (acf->acf_token != 0) {
  883. lex_token_destroy(acf->acf_token);
  884. }
  885. /* Free the filename string if any */
  886. if (acf->acf_filename != 0) {
  887. FREE(acf->acf_filename);
  888. }
  889. /* Free the ACLFile_t structure */
  890. FREE(acf);
  891. }
  892. }
  893. /*
  894. * Description (aclFileOpen)
  895. *
  896. * This function opens a specified filename and creates a structure
  897. * to contain information about the file during parsing. This
  898. * includes a handle for a LEX data stream for the file.
  899. *
  900. * Arguments:
  901. *
  902. * errp - error frame list pointer (may be null)
  903. * filename - name of file to be opened
  904. * flags - bit flags (unused - must be zero)
  905. * pacf - pointer to returned ACLFile_t pointer
  906. *
  907. * Returns:
  908. *
  909. * The return value is zero if the file is opened successfully, and
  910. * a pointer to the ACLFile_t is returned in the location specified
  911. * by 'pacf'. Otherwise a negative error code (ACLERRxxxx - see
  912. * aclerror.h) is returned, and an error frame will be generated if
  913. * an error list is provided.
  914. */
  915. int aclFileOpen(NSErr_t * errp,
  916. char * filename, int flags, ACLFile_t **pacf)
  917. {
  918. ACLFile_t * acf; /* pointer to ACL file structure */
  919. int rv; /* return value */
  920. int eid; /* error identifier */
  921. char * errmsg; /* system error message string */
  922. *pacf = 0;
  923. /* Allocate the ACLFile_t structure */
  924. acf = (ACLFile_t *)MALLOC(sizeof(ACLFile_t));
  925. if (acf == 0) goto err_nomem1;
  926. memset((void *)acf, 0, sizeof(ACLFile_t));
  927. acf->acf_filename = STRDUP(filename);
  928. acf->acf_lineno = 1;
  929. acf->acf_flags = flags;
  930. /* Create a LEX token object */
  931. rv = lex_token_new((pool_handle_t *)0, 32, 8, &acf->acf_token);
  932. if (rv < 0) goto err_nomem2;
  933. /* Open the file */
  934. acf->acf_fd = system_fopenRO(acf->acf_filename);
  935. if (acf->acf_fd == SYS_ERROR_FD) goto err_open;
  936. /* Create a LEX stream for the file */
  937. acf->acf_lst = lex_stream_create(aclStreamGet,
  938. (void *)acf->acf_fd, 0, 8192);
  939. if (acf->acf_lst == 0) goto err_nomem3;
  940. *pacf = acf;
  941. return 0;
  942. err_open: /* file open error */
  943. rv = ACLERROPEN;
  944. eid = ACLERR1900;
  945. errmsg = system_errmsg();
  946. nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
  947. goto punt;
  948. err_nomem1: /* MALLOC of ACLFile_t failed */
  949. rv = ACLERRNOMEM;
  950. eid = ACLERR1920;
  951. goto err_mem;
  952. err_nomem2: /* lex_token_new() failed */
  953. rv = ACLERRNOMEM;
  954. eid = ACLERR1940;
  955. goto err_mem;
  956. err_nomem3: /* lex_stream_create() failed */
  957. system_fclose(acf->acf_fd);
  958. rv = ACLERRNOMEM;
  959. eid = ACLERR1960;
  960. err_mem:
  961. nserrGenerate(errp, rv, eid, ACL_Program, 0);
  962. goto punt;
  963. punt:
  964. return rv;
  965. }
  966. /*
  967. * Description (aclGetDNSString)
  968. *
  969. * This function parses a DNS name specification, which consists
  970. * of a sequence of DNS name components separated by ".". Each
  971. * name component must start with a letter, and contains only
  972. * letters, digits, and hyphens. An exception is that the first
  973. * component may be the wildcard indicator, "*". This function
  974. * assumes that the current token already contains a TOKEN_STAR
  975. * or TOKEN_IDENT. The complete DNS name specification is
  976. * returned as the current token string.
  977. *
  978. * Arguments:
  979. *
  980. * errp - error frame list pointer (may be null)
  981. * acf - pointer to ACLFile_t for ACL file
  982. *
  983. * Returns:
  984. *
  985. * The character terminating the DNS name specification is returned
  986. * as the function value. The current token type is unchanged, but
  987. * the string associated with the current token contains the
  988. * complete DNS name specification. An error is indicated by a
  989. * negative return value, and an error frame is generated if an
  990. * error list is provided.
  991. */
  992. int aclGetDNSString(NSErr_t * errp, ACLFile_t * acf)
  993. {
  994. LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
  995. void * token = acf->acf_token; /* LEX token handle */
  996. int rv; /* result value */
  997. int eid; /* error id value */
  998. char linestr[16]; /* line number string buffer */
  999. /* The current token should be TOKEN_STAR or TOKEN_IDENT */
  1000. rv = acf->acf_ttype;
  1001. if ((rv != TOKEN_STAR) && (rv != TOKEN_IDENT)) goto err_dns1;
  1002. /* Loop to parse [ "." dns-component ]+ */
  1003. for (;;) {
  1004. /* Try to step over a "." */
  1005. rv = lex_next_char(lst, aclChTab, 0);
  1006. /* End of DNS string if there's not one there */
  1007. if (rv != '.') break;
  1008. /* Append the "." to the token string */
  1009. (void)lex_token_append(token, 1, ".");
  1010. /* Advance the input stream past the "." */
  1011. rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
  1012. /* Next we want to see a letter */
  1013. rv = lex_next_char(lst, aclChTab, 0);
  1014. /* Error if it's not there */
  1015. if (!lex_class_check(aclChTab, rv, CCM_LETTER)) goto err_dns2;
  1016. /* Append a string of letters, digits, hyphens to token */
  1017. rv = lex_scan_over(lst, aclChTab, (CCM_LETTER|CCM_DIGIT|CCM_HYPHEN),
  1018. token);
  1019. if (rv < 0) goto err_dns3;
  1020. }
  1021. punt:
  1022. return rv;
  1023. err_dns1:
  1024. eid = ACLERR2100;
  1025. rv = ACLERRPARSE;
  1026. goto err_ret;
  1027. err_dns2:
  1028. eid = ACLERR2120;
  1029. rv = ACLERRPARSE;
  1030. goto err_ret;
  1031. err_dns3:
  1032. eid = ACLERR2140;
  1033. rv = ACLERRPARSE;
  1034. goto err_ret;
  1035. err_ret:
  1036. sprintf(linestr, "%d", acf->acf_lineno);
  1037. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1038. goto punt;
  1039. }
  1040. int aclGetFileSpec(NSErr_t * errp, ACLFile_t * acf, int flags)
  1041. {
  1042. LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
  1043. void * token = acf->acf_token; /* LEX token handle */
  1044. char * tokenstr; /* token string pointer */
  1045. int rv; /* result value */
  1046. int eid; /* error id value */
  1047. char linestr[16]; /* line number string buffer */
  1048. /* Skip whitespace */
  1049. rv = lex_skip_over(lst, aclChTab, CCM_WS);
  1050. if (rv < 0) goto err_lex1;
  1051. /* Begin a new token string */
  1052. rv = lex_token_start(token);
  1053. rv = lex_scan_over(lst, aclChTab, CCM_FILENAME, token);
  1054. if (rv < 0) goto err_lex2;
  1055. tokenstr = lex_token(token);
  1056. if (!tokenstr || !*tokenstr) goto err_nofn;
  1057. punt:
  1058. return rv;
  1059. err_lex1:
  1060. eid = ACLERR2900;
  1061. goto err_parse;
  1062. err_lex2:
  1063. eid = ACLERR2920;
  1064. goto err_parse;
  1065. err_nofn:
  1066. eid = ACLERR2940;
  1067. err_parse:
  1068. rv = ACLERRPARSE;
  1069. sprintf(linestr, "%d", acf->acf_lineno);
  1070. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1071. goto punt;
  1072. }
  1073. /*
  1074. * Description (aclGetIPAddr)
  1075. *
  1076. * This function retrieves an IP address specification from a given
  1077. * input stream. The specification consists of an IP address expressed
  1078. * in the standard "." notation, possibly followed by whitespace and a
  1079. * netmask, also in "." form. The IP address and netmask values are
  1080. * returned. If no netmask is specified, a default value of 0xffffffff
  1081. * is returned.
  1082. *
  1083. * Arguments:
  1084. *
  1085. * errp - error frame list pointer (may be null)
  1086. * acf - pointer to ACLFile_t for ACL file
  1087. * pip - pointer to returned IP address value
  1088. * pmask - pointer to returned IP netmask value
  1089. *
  1090. * Returns:
  1091. *
  1092. * If successful, the return value identifies the type of the token
  1093. * following the IP address specification. This token type value is
  1094. * also returned in acf_ttype. An error is indicated by a negative
  1095. * error code (ACLERRxxxx - see aclerror.h), and an error frame will
  1096. * be generated if an error list is provided. The token type code in
  1097. * acf_ttype is TOKEN_ERROR when an error code is returned.
  1098. */
  1099. int aclGetIPAddr(NSErr_t * errp,
  1100. ACLFile_t * acf, IPAddr_t * pip, IPAddr_t * pmask)
  1101. {
  1102. LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
  1103. void * token = acf->acf_token; /* LEX token handle */
  1104. char * tokenstr; /* token string pointer */
  1105. IPAddr_t ipaddr; /* IP address */
  1106. IPAddr_t netmask; /* IP netmask */
  1107. int dotcnt; /* count of '.' seen in address */
  1108. int rv; /* result value */
  1109. int eid; /* error id value */
  1110. char linestr[16]; /* line number string buffer */
  1111. /* Set default return values */
  1112. *pip = 0;
  1113. *pmask = 0xffffffff;
  1114. rv = acf->acf_ttype;
  1115. /* The current token must be a number */
  1116. if (rv != TOKEN_NUMBER) {
  1117. /* No IP address present */
  1118. return rv;
  1119. }
  1120. /* Assume no netmask */
  1121. netmask = 0xffffffff;
  1122. for (dotcnt = 0;;) {
  1123. /* Append digits and letters to the current token */
  1124. rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
  1125. if (rv < 0) goto err_lex1;
  1126. /* Stop when no "." follows the digits and letters */
  1127. if (rv != '.') break;
  1128. /* Stop if we've already seen three "." */
  1129. if (++dotcnt > 3) break;
  1130. /* Advance past the "." */
  1131. (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
  1132. /* Check the next character for a "*" */
  1133. rv = lex_next_char(lst, aclChTab, 0);
  1134. if (rv == '*') {
  1135. /* Advance past the "*" */
  1136. (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
  1137. netmask <<= ((4-dotcnt)*8);
  1138. netmask = htonl(netmask);
  1139. while (dotcnt < 4) {
  1140. (void)lex_token_append(token, 2, ".0");
  1141. ++dotcnt;
  1142. }
  1143. break;
  1144. }
  1145. else {
  1146. /* Append the "." to the token string */
  1147. (void)lex_token_append(token, 1, ".");
  1148. }
  1149. }
  1150. /* Get a pointer to the token string */
  1151. tokenstr = lex_token(token);
  1152. /* A NULL pointer or an empty string is an error */
  1153. if (!tokenstr || !*tokenstr) goto err_noip;
  1154. /* Convert IP address to binary */
  1155. ipaddr = inet_addr(tokenstr);
  1156. if (ipaddr == (unsigned long)-1) goto err_badip;
  1157. /* Skip whitespace */
  1158. rv = lex_skip_over(lst, aclChTab, CCM_WS);
  1159. if (rv < 0) goto err_lex2;
  1160. /* A digit is the start of a netmask */
  1161. if ((netmask == 0xffffffff) && lex_class_check(aclChTab, rv, CCM_DIGIT)) {
  1162. /* Initialize token for network mask */
  1163. rv = lex_token_start(token);
  1164. for (dotcnt = 0;;) {
  1165. /* Collect token including digits, letters, and periods */
  1166. rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
  1167. if (rv < 0) goto err_lex3;
  1168. /* Stop when no "." follows the digits and letters */
  1169. if (rv != '.') break;
  1170. /* Stop if we've already seen three "." */
  1171. if (++dotcnt > 3) break;
  1172. /* Append the "." to the token string */
  1173. (void)lex_token_append(token, 1, ".");
  1174. /* Advance past the "." */
  1175. (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
  1176. }
  1177. /* Get a pointer to the token string */
  1178. tokenstr = lex_token(token);
  1179. /* A NULL pointer or an empty string is an error */
  1180. if (!tokenstr || !*tokenstr) goto err_nonm;
  1181. /* Convert netmask to binary. */
  1182. netmask = inet_addr(tokenstr);
  1183. if (netmask == (unsigned long)-1) {
  1184. /*
  1185. * Unfortunately inet_addr() doesn't distinguish between an
  1186. * error and a valid conversion of "255.255.255.255". So
  1187. * we check for it explicitly. Too bad if "0xff.0xff.0xff.0xff"
  1188. * is specified. Don't do that!
  1189. */
  1190. if (strcmp(tokenstr, "255.255.255.255")) goto err_badnm;
  1191. }
  1192. }
  1193. /* Return the IP address and netmask in host byte order */
  1194. *pip = ntohl(ipaddr);
  1195. *pmask = ntohl(netmask);
  1196. /* Get the token following the IP address (and netmask) */
  1197. rv = aclGetToken(errp, acf, 0);
  1198. punt:
  1199. acf->acf_ttype = (rv < 0) ? TOKEN_ERROR : rv;
  1200. return rv;
  1201. err_lex1:
  1202. eid = ACLERR2200;
  1203. rv = ACLERRPARSE;
  1204. goto err_ret;
  1205. err_lex2:
  1206. eid = ACLERR2220;
  1207. rv = ACLERRPARSE;
  1208. goto err_ret;
  1209. err_lex3:
  1210. eid = ACLERR2240;
  1211. rv = ACLERRPARSE;
  1212. goto err_ret;
  1213. err_noip:
  1214. eid = ACLERR2260;
  1215. rv = ACLERRPARSE;
  1216. goto err_ret;
  1217. err_badip:
  1218. eid = ACLERR2280;
  1219. rv = ACLERRPARSE;
  1220. goto err_ret;
  1221. err_nonm:
  1222. eid = ACLERR2300;
  1223. rv = ACLERRPARSE;
  1224. goto err_ret;
  1225. err_badnm:
  1226. eid = ACLERR2320;
  1227. rv = ACLERRPARSE;
  1228. goto err_ret;
  1229. err_ret:
  1230. sprintf(linestr, "%d", acf->acf_lineno);
  1231. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1232. goto punt;
  1233. }
  1234. /*
  1235. * Description (aclGetToken)
  1236. *
  1237. * This function retrieves the next token in an ACL definition file.
  1238. * It skips blank lines, comments, and white space. It updates
  1239. * the current line number as newlines are encountered.
  1240. *
  1241. * Arguments:
  1242. *
  1243. * errp - error frame list pointer (may be null)
  1244. * acf - pointer to ACLFile_t for ACL file
  1245. * flags - bit flags:
  1246. * AGT_NOSKIP - don't skip leading whitespace
  1247. * AGT_APPEND - append to token buffer
  1248. * (else start new token)
  1249. *
  1250. * Returns:
  1251. *
  1252. * The return value is a code identifying the next token if successful.
  1253. * This token type value is also returned in acf_ttype. An error
  1254. * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
  1255. * and an error frame will be generated if an error list is provided.
  1256. * The token type code in acf_ttype is TOKEN_ERROR when an error code
  1257. * is returned.
  1258. */
  1259. int aclGetToken(NSErr_t * errp, ACLFile_t * acf, int flags)
  1260. {
  1261. LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
  1262. void * token = acf->acf_token; /* LEX token handle */
  1263. int dospecial = 0; /* handle CCM_SPECIAL character */
  1264. int tv; /* token value */
  1265. int rv; /* result value */
  1266. int eid; /* error id */
  1267. char spech;
  1268. char linestr[16]; /* line number string buffer */
  1269. /* Begin a new token, unless AGT_APPEND is set */
  1270. if (!(flags & AGT_APPEND)) {
  1271. rv = lex_token_start(token);
  1272. }
  1273. /* Loop to read file */
  1274. tv = 0;
  1275. do {
  1276. /*
  1277. * If the AGT_NOSKIP flag is not set, skip whitespace (but not
  1278. * newline). If the flag is set, just get the next character.
  1279. */
  1280. rv = lex_skip_over(lst, aclChTab, (flags & AGT_NOSKIP) ? 0 : CCM_WS);
  1281. if (rv <= 0) {
  1282. if (rv < 0) goto err_lex1;
  1283. /* Exit loop if EOF */
  1284. if (rv == 0) {
  1285. tv = TOKEN_EOF;
  1286. break;
  1287. }
  1288. }
  1289. /* Analyze character after whitespace */
  1290. switch (rv) {
  1291. case '\n': /* newline */
  1292. /* Keep count of lines as we're skipping whitespace */
  1293. acf->acf_lineno += 1;
  1294. (void)lex_next_char(lst, aclChTab, CCM_NL);
  1295. break;
  1296. case '#': /* Beginning of comment */
  1297. /* Skip to a newline if so */
  1298. rv = lex_skip_to(lst, aclChTab, CCM_NL);
  1299. break;
  1300. case ';': /* End of statement */
  1301. tv = TOKEN_EOS;
  1302. dospecial = 1;
  1303. break;
  1304. case '@': /* at sign */
  1305. tv = TOKEN_AT;
  1306. dospecial = 1;
  1307. break;
  1308. case '+': /* plus sign */
  1309. tv = TOKEN_PLUS;
  1310. dospecial = 1;
  1311. break;
  1312. case '*': /* asterisk */
  1313. tv = TOKEN_STAR;
  1314. dospecial = 1;
  1315. break;
  1316. case '.': /* period */
  1317. tv = TOKEN_PERIOD;
  1318. dospecial = 1;
  1319. break;
  1320. case ',': /* comma */
  1321. tv = TOKEN_COMMA;
  1322. dospecial = 1;
  1323. break;
  1324. case '(': /* left parenthesis */
  1325. tv = TOKEN_LPAREN;
  1326. dospecial = 1;
  1327. break;
  1328. case ')': /* right parenthesis */
  1329. tv = TOKEN_RPAREN;
  1330. dospecial = 1;
  1331. break;
  1332. case '{': /* left brace */
  1333. tv = TOKEN_LBRACE;
  1334. dospecial = 1;
  1335. break;
  1336. case '}': /* right brace */
  1337. tv = TOKEN_RBRACE;
  1338. dospecial = 1;
  1339. break;
  1340. case '\"': /* double quote */
  1341. case '\'': /* single quote */
  1342. /* Append string contents to token buffer */
  1343. rv = lex_scan_string(lst, token, 0);
  1344. tv = TOKEN_STRING;
  1345. break;
  1346. default:
  1347. /* Check for identifier, beginning with a letter */
  1348. if (lex_class_check(aclChTab, rv, CCM_LETTER)) {
  1349. /* Append valid identifier characters to token buffer */
  1350. rv = lex_scan_over(lst, aclChTab, CCM_IDENT, token);
  1351. tv = TOKEN_IDENT;
  1352. break;
  1353. }
  1354. /* Check for a number, beginning with a digit */
  1355. if (lex_class_check(aclChTab, rv, CCM_DIGIT)) {
  1356. char digit;
  1357. /* Save the first digit */
  1358. digit = (char)rv;
  1359. /* Append the first digit to the token */
  1360. rv = lex_token_append(token, 1, &digit);
  1361. /* Skip over the first digit */
  1362. rv = lex_next_char(lst, aclChTab, CCM_DIGIT);
  1363. /* If it's '0', we might have "0x.." */
  1364. if (rv == '0') {
  1365. /* Pick up the next character */
  1366. rv = lex_next_char(lst, aclChTab, 0);
  1367. /* Is it 'x'? */
  1368. if (rv == 'x') {
  1369. /* Yes, append it to the token */
  1370. digit = (char)rv;
  1371. rv = lex_token_append(token, 1, &digit);
  1372. /* Step over it */
  1373. rv = lex_next_char(lst, aclChTab, CCM_LETTER);
  1374. }
  1375. }
  1376. /* Get more digits, if any */
  1377. rv = lex_scan_over(lst, aclChTab, CCM_DIGIT, token);
  1378. tv = TOKEN_NUMBER;
  1379. break;
  1380. }
  1381. /* Unrecognized character */
  1382. spech = *lst->lst_cp;
  1383. lex_token_append(token, 1, &spech);
  1384. lst->lst_cp += 1;
  1385. lst->lst_len -= 1;
  1386. tv = TOKEN_HUH;
  1387. break;
  1388. }
  1389. /* Handle CCM_SPECIAL character? */
  1390. if (dospecial) {
  1391. /* Yes, clear the flag for next time */
  1392. dospecial = 0;
  1393. /* Get the character and advance past it */
  1394. rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
  1395. /* Append the character to the token buffer */
  1396. spech = (char)rv;
  1397. (void)lex_token_append(token, 1, &spech);
  1398. }
  1399. }
  1400. while ((tv == 0) && (rv > 0));
  1401. if (rv < 0) {
  1402. tv = TOKEN_ERROR;
  1403. }
  1404. else rv = tv;
  1405. acf->acf_ttype = tv;
  1406. return rv;
  1407. err_lex1:
  1408. rv = ACLERRPARSE;
  1409. eid = ACLERR2400;
  1410. sprintf(linestr, "%d", acf->acf_lineno);
  1411. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1412. acf->acf_ttype = TOKEN_ERROR;
  1413. return rv;
  1414. }
  1415. /*
  1416. * Description (aclParseInit)
  1417. *
  1418. * This function is called to initialize the ACL parser. It
  1419. * creates a LEX character class table to assist in parsing.
  1420. *
  1421. * Arguments:
  1422. *
  1423. * None.
  1424. *
  1425. * Returns:
  1426. *
  1427. * If successful, the return value is zero. An error is indicated
  1428. * by a negative return value.
  1429. */
  1430. int aclParseInit()
  1431. {
  1432. int rv; /* result value */
  1433. /* Have we created the character class table yet? */
  1434. if (aclChTab == 0) {
  1435. /* No, initialize character classes for lexer processing */
  1436. rv = lex_class_create(classc, classv, &aclChTab);
  1437. if (rv < 0) goto err_nomem;
  1438. }
  1439. return 0;
  1440. err_nomem:
  1441. return ACLERRNOMEM;
  1442. }
  1443. /*
  1444. * Description (aclRealmSpecParse)
  1445. *
  1446. * This function parses an authentication realm specification. An
  1447. * authentication realm includes an authentication database and
  1448. * an authentication method. The syntax of a realm-spec is:
  1449. *
  1450. * realm-spec ::= "{" realm-directive-list "}" | "realm" realm-name
  1451. * realm-directive-list ::= realm-directive |
  1452. * realm-directive-list ";" realm-directive
  1453. * realm-directive ::= realm-db-directive | realm-meth-directive
  1454. * | realm-prompt-directive
  1455. * realm-db-directive ::= "database" db-file-path
  1456. * realm-meth-directive ::= "method" auth-method-name
  1457. * auth-method-name ::= "basic" | "SSL"
  1458. * realm-prompt-directive ::= "prompt" quote-char string quote-char
  1459. *
  1460. * Arguments:
  1461. *
  1462. * errp - error frame list pointer (may be null)
  1463. * acf - pointer to ACLFile_t for ACL file
  1464. * acc - pointer to ACContext_t structure
  1465. * rspp - pointer to RealmSpec_t pointer
  1466. *
  1467. * Returns:
  1468. *
  1469. * If successful, the return value is the token type of the token
  1470. * following the realm-spec, i.e. either the first token after a
  1471. * realm-name or the first token after the closing "}". It is the
  1472. * caller's responsibility to validate this token as a legitimate
  1473. * successor of a realm-spec. If a parsing error occurs in the
  1474. * middle of a realm-spec, the return value is ACLERRPARSE, and an
  1475. * error frame is generated if an error list is provided. For
  1476. * other kinds of errors a negative error code (from aclerror.h)
  1477. * is returned.
  1478. */
  1479. int aclRealmSpecParse(NSErr_t * errp,
  1480. ACLFile_t * acf, ACContext_t * acc, RealmSpec_t **rspp)
  1481. {
  1482. void * token = acf->acf_token; /* handle for current token */
  1483. char * tokenstr; /* current token string */
  1484. RealmSpec_t * rsp; /* realm spec pointer */
  1485. RealmSpec_t * nrsp; /* named realm spec pointer */
  1486. int rv; /* result value */
  1487. int eid; /* error id value */
  1488. char linestr[16]; /* line number string buffer */
  1489. rv = acf->acf_ttype;
  1490. /* Is the current token a "{" ? */
  1491. if (rv != TOKEN_LBRACE) {
  1492. /* No, could it be KEYWORD_REALM? */
  1493. if (rv == TOKEN_IDENT) {
  1494. tokenstr = lex_token(token);
  1495. if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
  1496. /* Yes, step to the realm name */
  1497. rv = aclGetToken(errp, acf, 0);
  1498. if (rv != TOKEN_IDENT) {
  1499. if (rv < 0) goto punt;
  1500. goto err_rlmname;
  1501. }
  1502. tokenstr = lex_token(token);
  1503. /* Look up the named realm specification */
  1504. rv = symTableFindSym(acc->acc_stp, tokenstr, ACLSYMREALM,
  1505. (void **)&nrsp);
  1506. if (rv < 0) goto err_undrlm;
  1507. /* Return the named realm specification */
  1508. *rspp = nrsp;
  1509. /* Step to the token after the realm name */
  1510. rv = aclGetToken(errp, acf, 0);
  1511. }
  1512. }
  1513. return rv;
  1514. }
  1515. /* Step to the token after the "{" */
  1516. rv = aclGetToken(errp, acf, 0);
  1517. if (rv < 0) goto punt;
  1518. rsp = *rspp;
  1519. if (rsp == 0) {
  1520. rsp = (RealmSpec_t *)MALLOC(sizeof(RealmSpec_t));
  1521. if (rsp == 0) goto err_nomem;
  1522. memset((void *)rsp, 0, sizeof(RealmSpec_t));
  1523. rsp->rs_sym.sym_type = ACLSYMREALM;
  1524. *rspp = rsp;
  1525. }
  1526. /* Loop for each realm-directive */
  1527. for (;; rv = aclGetToken(errp, acf, 0)) {
  1528. if (rv != TOKEN_IDENT) {
  1529. /* Exit loop on "}" */
  1530. if (rv == TOKEN_RBRACE) break;
  1531. /* Ignore null directives */
  1532. if (rv == TOKEN_EOS) continue;
  1533. /* Otherwise need an identifier to start a directive */
  1534. goto err_nodir;
  1535. }
  1536. tokenstr = lex_token(token);
  1537. /* Figure out which realm-directive this is */
  1538. if (!strcasecmp(tokenstr, KEYWORD_DATABASE)) {
  1539. /* Get a file specification for the database */
  1540. rv = aclGetToken(errp, acf, 0);
  1541. if (rv != TOKEN_STRING) {
  1542. if (rv < 0) goto punt;
  1543. goto err_nodb;
  1544. }
  1545. rsp->rs_realm.rlm_dbname = lex_token_take(token);
  1546. rsp->rs_realm.rlm_aif = &NSADB_AuthIF;
  1547. }
  1548. else if (!strcasecmp(tokenstr, KEYWORD_METHOD)) {
  1549. /* Step to the method identifier */
  1550. rv = aclGetToken(errp, acf, 0);
  1551. if (rv != TOKEN_IDENT) {
  1552. if (rv < 0) goto punt;
  1553. goto err_nometh;
  1554. }
  1555. tokenstr = lex_token(token);
  1556. /* Interpret method name and set method in realm structure */
  1557. if (!strcasecmp(tokenstr, KEYWORD_BASIC)) {
  1558. rsp->rs_realm.rlm_ameth = AUTH_METHOD_BASIC;
  1559. }
  1560. else if (!strcasecmp(tokenstr, KEYWORD_SSL) && server_enterprise) {
  1561. rsp->rs_realm.rlm_ameth = AUTH_METHOD_SSL;
  1562. }
  1563. else goto err_badmeth;
  1564. }
  1565. else if (!strcasecmp(tokenstr, KEYWORD_PROMPT)) {
  1566. /* Step to the realm prompt string */
  1567. rv = aclGetToken(errp, acf, 0);
  1568. if ((rv != TOKEN_STRING) && (rv != TOKEN_IDENT)) {
  1569. if (rv < 0) goto punt;
  1570. goto err_noprompt;
  1571. }
  1572. /* Reference a copy of the prompt string from the realm */
  1573. rsp->rs_realm.rlm_prompt = lex_token_take(token);
  1574. }
  1575. else goto err_baddir;
  1576. /* Get the token after the realm-directive */
  1577. rv = aclGetToken(errp, acf, 0);
  1578. /* Need a ";" to keep going */
  1579. if (rv != TOKEN_EOS) break;
  1580. }
  1581. if (rv != TOKEN_RBRACE) goto err_rbrace;
  1582. /* Get the token after the realm-spec */
  1583. rv = aclGetToken(errp, acf, 0);
  1584. punt:
  1585. return rv;
  1586. err_rlmname:
  1587. eid = ACLERR2500;
  1588. goto err_parse;
  1589. err_undrlm:
  1590. eid = ACLERR2520;
  1591. rv = ACLERRUNDEF;
  1592. goto err_sym;
  1593. err_nomem:
  1594. eid = ACLERR2540;
  1595. rv = ACLERRNOMEM;
  1596. goto ret_err;
  1597. err_nodir:
  1598. eid = ACLERR2560;
  1599. goto err_parse;
  1600. err_nodb:
  1601. eid = ACLERR2570;
  1602. goto err_parse;
  1603. err_nometh:
  1604. eid = ACLERR2580;
  1605. goto err_parse;
  1606. err_badmeth:
  1607. eid = ACLERR2600;
  1608. goto err_sym;
  1609. err_noprompt:
  1610. eid = ACLERR2605;
  1611. goto err_parse;
  1612. err_baddir:
  1613. eid = ACLERR2610;
  1614. goto err_sym;
  1615. err_rbrace:
  1616. eid = ACLERR2620;
  1617. goto err_parse;
  1618. err_sym:
  1619. sprintf(linestr, "%d", acf->acf_lineno);
  1620. nserrGenerate(errp, rv, eid, ACL_Program,
  1621. 3, acf->acf_filename, linestr, tokenstr);
  1622. goto punt;
  1623. err_parse:
  1624. rv = ACLERRPARSE;
  1625. ret_err:
  1626. sprintf(linestr, "%d", acf->acf_lineno);
  1627. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1628. goto punt;
  1629. }
  1630. /*
  1631. * Description (aclRightsParse)
  1632. *
  1633. * This function parse an access rights list. The syntax for an
  1634. * access rights list is:
  1635. *
  1636. * rights-list ::= "(" list-of-rights ")"
  1637. * list-of-rights ::= rights-elem | list-of-rights "," rights-elem
  1638. * rights-elem ::= right-name | "+" rights-def-name
  1639. * right-name ::= identifier
  1640. * rights-def-name ::= identifier
  1641. *
  1642. * An element of a rights list is either the name of a particular
  1643. * access right (e.g. Read), or the name associated with an
  1644. * external definition of an access rights list, preceded by "+"
  1645. * (e.g. +editor-rights). The list is enclosed in parentheses,
  1646. * and the elements are separated by commas.
  1647. *
  1648. * This function adds to a list of rights provided by the caller.
  1649. * Access rights are internally assigned unique integer identifiers,
  1650. * and a symbol table is maintained to map an access right name to
  1651. * its identifier.
  1652. *
  1653. * Arguments:
  1654. *
  1655. * errp - error frame list pointer (may be null)
  1656. * acf - pointer to ACLFile_t for ACL file
  1657. * acc - pointer to ACContext_t structure
  1658. * rights - pointer to rights list head
  1659. *
  1660. * Returns:
  1661. *
  1662. * The return value is a code identifying the next token if successful.
  1663. * End-of-stream is indicated by a return value of TOKEN_EOF. An error
  1664. * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
  1665. * and an error frame will be generated if an error list is provided.
  1666. */
  1667. int aclRightsParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc,
  1668. RightSpec_t **rights)
  1669. {
  1670. void * token = acf->acf_token; /* LEX token handle */
  1671. char * ename; /* element name string pointer */
  1672. RightSpec_t * rsp; /* rights specification pointer */
  1673. RightSpec_t * nrsp; /* named rights spec pointer */
  1674. RightDef_t * rdp; /* right definition pointer */
  1675. int rv; /* result value */
  1676. int eid; /* error id */
  1677. char linestr[16]; /* line number string buffer */
  1678. /* Look for a left parenthesis */
  1679. if (acf->acf_ttype != TOKEN_LPAREN) {
  1680. /* No rights list present */
  1681. return 0;
  1682. }
  1683. rsp = *rights;
  1684. /* Create a RightSpec_t if we don't have one */
  1685. if (rsp == 0) {
  1686. rsp = (RightSpec_t *)MALLOC(sizeof(RightSpec_t));
  1687. if (rsp == 0) goto err_nomem1;
  1688. memset((void *)rsp, 0, sizeof(RightSpec_t));
  1689. rsp->rs_sym.sym_type = ACLSYMRDEF;
  1690. *rights = rsp;
  1691. }
  1692. /* Parse list elements */
  1693. for (;;) {
  1694. /* Look for an identifier */
  1695. rv = aclGetToken(errp, acf, 0);
  1696. if (rv != TOKEN_IDENT) {
  1697. /* No, maybe a "+" preceding a rights definition name? */
  1698. if (rv != TOKEN_PLUS) {
  1699. /* One more chance, we'll allow the closing ")" after "," */
  1700. if (rv != TOKEN_RPAREN) {
  1701. /* No, bad news */
  1702. if (rv < 0) goto punt;
  1703. goto err_elem;
  1704. }
  1705. /* Got right paren after comma */
  1706. break;
  1707. }
  1708. /* Got a "+", try for the rights definition name */
  1709. rv = aclGetToken(errp, acf, 0);
  1710. if (rv != TOKEN_IDENT) {
  1711. if (rv < 0) goto punt;
  1712. goto err_rdef;
  1713. }
  1714. /* Get a pointer to the token string */
  1715. ename = lex_token(token);
  1716. /* See if it matches a rights definition in the symbol table */
  1717. rv = symTableFindSym(acc->acc_stp, ename, ACLSYMRDEF,
  1718. (void **)&nrsp);
  1719. if (rv) goto err_undef;
  1720. /*
  1721. * Merge the rights from the named rights list into the
  1722. * current rights list.
  1723. */
  1724. rv = uilMerge(&rsp->rs_list, &nrsp->rs_list);
  1725. if (rv < 0) goto err_nomem2;
  1726. }
  1727. else {
  1728. /* The current token is an access right name */
  1729. /* Get a pointer to the token string */
  1730. ename = lex_token(token);
  1731. /* Find or create an access right definition */
  1732. rv = aclRightDef(errp, acc, ename, &rdp);
  1733. if (rv < 0) goto err_radd;
  1734. /* Add the id for this right to the current rights list */
  1735. rv = usiInsert(&rsp->rs_list, rdp->rd_id);
  1736. if (rv < 0) goto err_nomem3;
  1737. }
  1738. rv = aclGetToken(errp, acf, 0);
  1739. /* Want a comma to continue the list */
  1740. if (rv != TOKEN_COMMA) {
  1741. /* A right parenthesis will end the list nicely */
  1742. if (rv == TOKEN_RPAREN) {
  1743. /* Get the first token after the rights list */
  1744. rv = aclGetToken(errp, acf, 0);
  1745. break;
  1746. }
  1747. /* Anything else is an error */
  1748. if (rv < 0) goto punt;
  1749. goto err_list;
  1750. }
  1751. }
  1752. return rv;
  1753. err_elem:
  1754. eid = ACLERR2700;
  1755. rv = ACLERRSYNTAX;
  1756. goto err_ret;
  1757. err_rdef:
  1758. eid = ACLERR2720;
  1759. rv = ACLERRSYNTAX;
  1760. goto err_ret;
  1761. err_undef:
  1762. eid = ACLERR2740;
  1763. rv = ACLERRUNDEF;
  1764. sprintf(linestr, "%d", acf->acf_lineno);
  1765. nserrGenerate(errp, rv, eid, ACL_Program,
  1766. 3, acf->acf_filename, linestr, ename);
  1767. return rv;
  1768. err_nomem1:
  1769. eid = ACLERR2760;
  1770. goto err_nomem;
  1771. err_nomem2:
  1772. eid = ACLERR2780;
  1773. goto err_nomem;
  1774. err_radd:
  1775. eid = ACLERR2800;
  1776. goto err_ret;
  1777. err_nomem3:
  1778. eid = ACLERR2820;
  1779. goto err_nomem;
  1780. err_nomem:
  1781. rv = ACLERRNOMEM;
  1782. goto err_ret;
  1783. err_list:
  1784. eid = ACLERR2840;
  1785. rv = ACLERRSYNTAX;
  1786. err_ret:
  1787. sprintf(linestr, "%d", acf->acf_lineno);
  1788. nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
  1789. punt:
  1790. return rv;
  1791. }
  1792. /*
  1793. * Description (aclStreamGet)
  1794. *
  1795. * This function is the stream read function designated by
  1796. * aclFileOpen() to read the file associated with the LEX stream
  1797. * it creates. It reads the next chunk of the file into the
  1798. * stream buffer.
  1799. *
  1800. * Arguments:
  1801. *
  1802. * lst - pointer to LEX stream structure
  1803. *
  1804. * Returns:
  1805. *
  1806. * The return value is the number of bytes read if successful.
  1807. * A return value of zero indicates end-of-file. An error is
  1808. * indicated by a negative return value.
  1809. */
  1810. int aclStreamGet(LEXStream_t * lst)
  1811. {
  1812. SYS_FILE fd = (SYS_FILE)(lst->lst_strmid);
  1813. int len;
  1814. len = system_fread(fd, lst->lst_buf, lst->lst_buflen);
  1815. if (len >= 0) {
  1816. lst->lst_len = len;
  1817. lst->lst_cp = lst->lst_buf;
  1818. }
  1819. return len;
  1820. }